缘由
开发一个下载图片的爬虫,原网站时不时变动,导致爬虫经常会挂掉,尤其在最终下载图片的环节。想着模拟浏览器另存为的方式可能会更健壮些,不那么容易挂。另外也一直想学习下 Selenium。
Selenium
1. 驱动和环境
使用的是 Python 环境,Selenium 的安装直接 pip install selenium
即可。
浏览器使用的是 Firefox,驱动是 geckdriver。将下载后的文件放入到 Firefox 安装目录下,如 C:\Program Files\Mozilla Firefox
。
环境变量的配置也是 Firefox 安装目录,而不需要到文件。这里坑了好久,一直报找不到驱动的错误,原因是写成了 C:\Program Files\Mozilla Firefox\geckdriver.exe
。
2. 请求网站
以掘金网站博客 cxuan读者的外包面试之旅 为例。
driver = webdriver.Firefox()
driver.get("https://juejin.im/post/6857394127064006663")
此时没有问题的话,浏览器会自动打开网站。
3. 滚动加载
此时若直接获取图片,只会获取获取到一两张。因为大多数网站采用 Ajax 方式,页面滚动到图片才加载,所有就需要模拟页面滚动了。execute_script
方法调用 js 可实现滚动操作。
# 获取内容高度
all_height = driver.execute_script("return document.body.scrollHeight")
# 循环往下滚动,每次滚1024高,间隔1秒
scroll_height = 1024
for i in range(int(all_height/scroll_height)):
driver.execute_script("window.scrollTo(0, {0});".format(i*scroll_height))
time.sleep(1)
如果遇到无限加载的页面,可以参考 stackoverflow 的 回答。代码如下:
SCROLL_PAUSE_TIME = 0.5
# Get scroll height
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
# Scroll down to bottom
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# Wait to load page
time.sleep(SCROLL_PAUSE_TIME)
# Calculate new scroll height and compare with last scroll height
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
4. 查找元素
图片加载完成后,就可以定位元素找到图片地址了。这里知识和之前学 Scrapy 的差不多。
# 定位到文章节点
image_content = driver.find_element_by_css_selector(".article")
# 获取文章内img标签
image_elems = image_content.find_elements_by_css_selector("img")
# 图片链接存放到list中
image_list = []
for i in image_elems:
# print(i.get_attribute("src"))
image_list.append(i.get_attribute("src"))
5. 调用右键
ActionChains
方法可调用右键。右键之前需先定位到元素。
driver = webdriver.Firefox()
driver.get("https://img-blog.csdnimg.cn/20191104151241389.png")
actionChains = ActionChains(driver)
body = driver.find_element_by_css_selector("body > img")
actionChains.context_click(body).perform()
time.sleep(3)
driver.close()
然后就没有然后了。
Selenium 好像对页面而无法右键菜单进行操作,网上也搜了好久,应该得联合 js 操作,感觉挺麻烦的。后来找到了 PyAutoGUI
这个库。
PyAutoGUI
安装直接 pip install pyautogui
即可。
使用超级简单:
write()
写入字符press()
按下按键,相当于keyDown()
和keyUp()
的包装hotkey()
可以传递几个键字符串,这些字符串将按顺序按下,然后以相反的顺序释放
如火狐的另存为在第三个位置,只需要按方向键下三次,然后回车即可跳出保存对话框。代码如下:
pyautogui.press(['down','down', 'down', 'enter'])
由于是图片地址,本 DEMO 其实只需要键入 Ctrl + s
就可以跳出保存对话框。代码如下:
# 浏览器另存为保存图片
for i in image_list:
driver.get(i)
# 图片地址,直接 ctrl+s,不用另存为
pyautogui.hotkey('ctrl', 's')
pyautogui.sleep(1)
# 采用时间戳命名,防止名称重复弹出确认框
pyautogui.write(str(int(time.time() * 1000)), interval=0.1)
pyautogui.press('enter')
pyautogui.sleep(1)
整体代码如下:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
import pyautogui
import time
def driver_JJ():
# 请求网站
driver = webdriver.Firefox()
driver.get("https://juejin.im/post/6857394127064006663")
# 获取内容高度
all_height = driver.execute_script("return document.body.scrollHeight")
# 循环往下滚动,每次滚1024高,间隔1秒
scroll_height = 1024
for i in range(int(all_height/scroll_height)):
driver.execute_script("window.scrollTo(0, {0});".format(i*scroll_height))
time.sleep(1)
# 定位到文章节点
image_content = driver.find_element_by_css_selector(".article")
# 获取文章内img标签
image_elems = image_content.find_elements_by_css_selector("img")
# 图片链接存放到list中
image_list = []
for i in image_elems:
print(i.get_attribute("src"))
image_list.append(i.get_attribute("src"))
# 浏览器另存为保存图片
for i in image_list:
driver.get(i)
# 图片地址,直接 ctrl+s,不用另存为
pyautogui.hotkey('ctrl', 's')
pyautogui.sleep(1)
# 采用时间戳命名,防止名称重复弹出确认框
pyautogui.write(str(int(time.time() * 1000)), interval=0.1)
pyautogui.press('enter')
pyautogui.sleep(1)
driver.close()
def main():
driver_JJ()
if __name__ == '__main__':
main()
关联阅读
Last modified on 2020-08-05