0%

Selenium 实现 web 爬虫

Selenium automates browsers. That’s it! What you do with that power is entirely up to you.

selenium 可以让浏览器自动化,搭配一些浏览器,浏览器驱动,比如 谷歌火狐PhantomJS 等,可以实现 web 自动化测试,也可以实现页面信息爬虫,但是如果对爬虫性能要求比较高,该方案则不适合。使用无头浏览器选项可以把项目部署到 linux 服务器上,做到 web 自动测试。

selenium 存在多个语言版本,这里我们选用的是 python

接下来以 谷歌 浏览器来作为我们的浏览器驱动,火狐 同理,可能只是存在部分选项配置上的差异,PhantomJS 不建议搭配使用了,官方已经不再支持,使用别的浏览器也能支持无头模式。

代码中使用的示例网站来自 崔庆才 部署的爬虫练习平台,万分感谢~

环境

  • OS Windows
  • python3.6
  • 谷歌浏览器 94.0.4606.54

安装 chromedriver

下载 找到与自己浏览器版本,系统 os 相适配的驱动下载,大版本一样就行,比如 94.xx.xx.xx

下载完成解压后会得到一个可执行文件 chromedriver.exe ,如果是 linux 或者 mac 版本则是 chromedriver,把这个文件加入可执行环境变量中,如果没有加入后面程序调用指定绝对路径

python 下载 selenium 包

1
pip install selenium

小试牛刀

实例代码参考自官方网站文档

test.py
1
2
3
4
5
6
7
8
9
10
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
import selenium.webdriver.support.expected_conditions as EC

with webdriver.Chrome(executable_path=r"D:\browser driver\chromedriver.exe") as driver:
wait = WebDriverWait(driver, 10)
driver.get("https://ssr1.scrape.center/")
print(driver.title)

执行命令 python test.py,执行完成以后可以看到控制台输出了网站标题

其他更多可使用的 api 可以在文档中查找

实战-1

https://ssr1.scrape.center/ 为例,该站所有的电影信息抓取下来,详细逻辑看代码注释

主要是训练对捕获元素api的使用

scrapy_test1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
import selenium.webdriver.support.expected_conditions as EC
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('--headless') # 使用无头模式,则不会弹出浏览器,适用于无ui渲染的os,比如部署到 linux 服务器

driver = webdriver.Chrome(executable_path=r"D:\browser driver\chromedriver.exe", chrome_options=options) # 注意驱动的可执行路径换成自己的
wait = WebDriverWait(driver, 10)
driver.get("https://ssr1.scrape.center/")

while True:
movieRows = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.el-card.item'))) # 先把包含每行电影信息的元素找出来

for i, movieRow in enumerate(movieRows):
movie = dict()

# 获取封面图片地址
imageElement = movieRow.find_element_by_class_name('cover')
movie["cover"] = imageElement.get_attribute('src')

# 获取电影标题
titleElement = movieRow.find_element_by_css_selector('div > div > div:nth-child(2) > a > h2')
movie["title"] = titleElement.text

# 电影标签
tagsElement = movieRow.find_elements_by_css_selector('div > div > div:nth-child(2) > div.categories > button > span')
movie["tags"] = []
for i, tagElement in enumerate(tagsElement):
movie["tags"].append(tagElement.text)

# 电影上映地区
areaElement = movieRow.find_element_by_css_selector('div > div > div:nth-child(2) > div:nth-child(3) > span:first-child')
movie["area"] = areaElement.text

# 电影时长
timeElement = movieRow.find_element_by_css_selector('div > div > div:nth-child(2) > div:nth-child(3) > span:last-child')
movie["time_long"] = titleElement.text

# 电影评分
rateElement = movieRow.find_element_by_css_selector('div > div > div:nth-child(3) > p:first-child')
movie["rate"] = rateElement.text

print(movie)

nextPageBtn = driver.find_element_by_class_name('btn-next')
btnStatus = nextPageBtn.get_attribute("disabled")
if btnStatus == "true":
break
nextPageBtn.click()

driver.quit()

实战-2

模拟登录 https://login2.scrape.center/login

scrapy_test2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
import selenium.webdriver.support.expected_conditions as EC
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('--headless') # 使用无头模式,则不会弹出浏览器,适用于无ui渲染的os,比如部署到 linux 服务器

driver = webdriver.Chrome(executable_path=r"D:\browser driver\chromedriver.exe", chrome_options=options)
wait = WebDriverWait(driver, 10)
driver.get("https://login2.scrape.center/login")

usernameInput = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="app"]/div[2]/div/div/div/div/div/form/div[1]/div/div/input'))) # 用户名输入框
passwordInput = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="app"]/div[2]/div/div/div/div/div/form/div[2]/div/div/input'))) # 密码输入框
loginBtn = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="app"]/div[2]/div/div/div/div/div/form/div[3]/div/input'))) # 登录按钮
usernameInput.send_keys("admin") # 在用户框中输入 admin
passwordInput.send_keys("admin") # 在密码框中输入 admin
loginBtn.click() # 点击登录按钮
username = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="header"]/div/div/div[2]/div/button/span'))) # 登录以后获取登录用户信息
print(username.text)

这个案例主要说明怎么模拟输入,点击页面元素,例子中捕获元素我们换了一种与案例1不一样的捕获方式:WebDriverWait,当我们捕获元素时,如果 dom 中没有这个元素,会抛出 NoSuchElement 异常,因为页面访问和加载是需要时间的,有时页面打开了,但是页面的一些元素还没渲染出来,程序已经快速执行到相应的地方了,这时却没有拿到元素,就会有可能抛出异常。解决这种问题,一个是可以人为的让程序沉睡一段时间后再继续执行,另外一种则是用 selenium 提供的 wait 阻塞,阻塞指定时间内还没有捕获才抛出异常,捕获到就继续往下执行。

  1. 人为程序睡眠
1
2
3
import time
time.sleep(1) # 沉睡 1s
pass
  1. 使用 wait 参考上方案例

这两种方法,大部分情况下推荐使用第二种,一是代码更可观,不会出现一大堆 sleep,二是我们不知道设定 sleep 的时间为多少比较好,少了程序可能没捕捉到,多了程序运行时间会变长。不过这没有绝对性,有时也需要用沉睡的方法,看情况使用就行。

总结

chromedriver options 这里记录了 chromedriver 可用的一些 option

这里只对 selenium 做了简单的使用介绍,它还有很多强大的功能可以使用,可以让我们做更多的事情。

爬虫虽好,但不要贪杯越界哦