Python爬虫学习之selenium
概述
在之前,我们学习了使用requests进行爬虫以及使用XPATH等工具提取数据。但是这些方法只能爬取静态网页,无法获取js渲染的数据。后来我们通过分析ajax,使我们可以通过requests来获取数据,这其实也是js渲染的一种情形。但是不是所有的js渲染都使用ajax,这样我们就无法通过ajax来获取数据。而有的页面即便使用ajax获取数据,但是由于加密了很多的参数,很难直接通过ajax获取数据。
为了解决这一问题,我们可以使用Selenium、Splash、Pyppetter、Playwright等库。这些库可以模拟浏览器运行,所看即所得,无需担心js渲染的问题。
准备工作
# pip命令
pip install selenium
# pip3命令
pip3 install selenium
# conda命令
conda install selenium
此外,还可以通过wheel安装,在PyPi下载对应的wheel文件并通过pip命令安装。
pip install 下载的文件名全称
此外,使用selenium需要浏览器配合,本文使用的是chrome,所以需要安装chrome
以及 ChromeDriver
驱动。
基本使用
import time
from selenium import webdriver
browser = webdriver.Chrome()
try:
browser.get('https://www.baidu.com')
print(browser.page_source)
finally:
time.sleep(2)
browser.close()
运行代码后发现,自动弹出来一个Chrome浏览器,打开了百度页面并在控制台输出了该页面的html数据,等待两秒后关闭了浏览器。
如代码所示,我们使用get()
方法来请求网页,参数为URL。使用page_source来获取网页数据。
这里使用了Chrome浏览器演示,如果使用其他浏览器,参考一下代码。
from selenium import webdriver
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.Safari()
进阶操作
查找结点
单个节点
如果我们需要使用selenium利用百度来搜索信息,那么需要获取搜索框输入条件,再点击搜索按钮。要完成这些操作,首先需要知道输入框与按钮所在位置。sellenium提供了一系列方法供我们获取想要的节点。如find_element()
。
分析源代码可知,搜索输入框的id
是kw
,class
是s_ipt
,name
是wd
,因此我们可以通过以下代码获取输入框。
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
try:
browser.get('https://www.baidu.com')
# 通过id获取
input1 = browser.find_element(By.ID, 'kw')
# 通过class获取
input2 = browser.find_element(By.CLASS_NAME, 's_ipt')
# 通过name获取
input3 = browser.find_element(By.NAME, 'wd')
# 通过xpath获取
input4 = browser.find_element(By.XPATH, '//*[@id="kw"]')
print(input1)
print(input2)
print(input3)
print(input4)
finally:
browser.close()
<selenium.webdriver.remote.webelement.WebElement (session="a7a4dd9ea41cc319f025623b895bf83c", element="1444d183-6b9d-4eb0-acce-39825ca6337b")>
<selenium.webdriver.remote.webelement.WebElement (session="a7a4dd9ea41cc319f025623b895bf83c", element="1444d183-6b9d-4eb0-acce-39825ca6337b")>
<selenium.webdriver.remote.webelement.WebElement (session="a7a4dd9ea41cc319f025623b895bf83c", element="1444d183-6b9d-4eb0-acce-39825ca6337b")>
<selenium.webdriver.remote.webelement.WebElement (session="a7a4dd9ea41cc319f025623b895bf83c", element="1444d183-6b9d-4eb0-acce-39825ca6337b")>
从结果可以看到,输出的都是同一个节点。
以下列出了所有获取单个节点的By值。
By.ID
By.CLASS_NAME
By.NAME
By.XPATH
By.CSS_SELECTOR
By.LINK_TEXT
By.PARTIAL_LINK_TEXT
By.TAG_NAME
多个节点
如果查找的目标有多个,那么使用以上方法只能获取第一个节点。如果要获取所有的节点,使用find_elements()
方法
如图,我们要获取红线标识位置的节点,可以使用以下代码:
browser = webdriver.Chrome()
try:
browser.get('https://www.baidu.com')
alink = browser.find_elements(By.XPATH, '//*[@id="s-top-left"]/a')
print(alink)
finally:
browser.close()
[<selenium.webdriver.remote.webelement.WebElement (session="37ae9a9a652b2b7102dc6213c554d58e", element="663d47da-7ad1-49f0-a7ab-4438012b95e6")>, <selenium.webdriver.remote.webelement.WebElement (session="37ae9a9a652b2b7102dc6213c554d58e", element="508d9e09-94dd-4a96-99e8-46af9234ede7")>, <selenium.webdriver.remote.webelement.WebElement (session="37ae9a9a652b2b7102dc6213c554d58e", element="e97c2b07-c13a-4326-afcf-8d0c723642bc")>, <selenium.webdriver.remote.webelement.WebElement (session="37ae9a9a652b2b7102dc6213c554d58e", element="fb62093c-eec0-4821-af4a-966284577f85")>, <selenium.webdriver.remote.webelement.WebElement (session="37ae9a9a652b2b7102dc6213c554d58e", element="75b9c90b-3553-4120-8b8c-48f639a3f453")>, <selenium.webdriver.remote.webelement.WebElement (session="37ae9a9a652b2b7102dc6213c554d58e", element="de58886c-8c11-45c1-bc79-966d42a9f21d")>, <selenium.webdriver.remote.webelement.WebElement (session="37ae9a9a652b2b7102dc6213c554d58e", element="4cecec57-8e34-49b2-8bf4-99b25bce46df")>]
可以看到结果为列表类型,既符合条件的所有节点。
获取节点的By值与获取单节点的By值相同。
节点交互
当我们获取到搜索框的节点时,需要输入我们想要搜索的信息,这时可以使用send_keys()
方法实现。
清空文字时使用clear()
方法,输入完搜索信息之后点击搜索按钮使用click()方法。代码如下:
browser = webdriver.Chrome()
try:
browser.get('https://www.baidu.com')
input1 = browser.find_element(By.ID, 'kw')
btn = browser.find_element(By.XPATH, '//*[@id="su"]')
input1.send_keys('汽车')
btn.click()
finally:
time.sleep(2)
browser.close()
执行JavaScript
selenium可以执行js代码,使用execute_script()
方法。如下所示,将下拉条滑倒最下面。
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
获取节点信息
前面说过,可以使用page_source
获取网页源码,之后可以使用解析库来提取信息。而selenium也提供了相关的方法与属性来获取节点信息。
获取节点属性 get_attrbute()
browser = webdriver.Chrome()
try:
browser.get('https://www.baidu.com')
alink = browser.find_elements(By.XPATH, '//*[@id="s-top-left"]/a')
for al in alink:
print(al.get_attribute("href"))
finally:
browser.close()
http://news.baidu.com/
https://www.hao123.com/?src=from_pc
http://map.baidu.com/
http://tieba.baidu.com/
https://haokan.baidu.com/?sfrom=baidu-top
http://image.baidu.com/
https://pan.baidu.com/?from=1026962h
这里使用 get_attribute()
方法获取所有的a
节点的href
属性。如果需要其他属性值,只需要传入属性名即可。
获取节点文本值 text
browser = webdriver.Chrome()
try:
browser.get('https://www.baidu.com')
alink = browser.find_elements(By.XPATH, '//*[@id="s-top-left"]/a')
for al in alink:
# print(al.get_attribute("href"))
print(al.text)
finally:
browser.close()
新闻
hao123
地图
贴吧
视频
图片
网盘
对于文本,直接使用text属性即可。
获取id、位置、标签名、大小
browser = webdriver.Chrome()
try:
browser.get('https://www.baidu.com')
alink = browser.find_elements(By.XPATH, '//*[@id="s-top-left"]/a')
for al in alink:
# print(al.get_attribute("href"))
# print(al.text)
print(al.id)
print(al.location)
print(al.tag_name)
print(al.size)
finally:
browser.close()
# 这里只显示第一个a节点的内容
574bed25-08ae-46bd-b59b-5c661a95bf64
{'x': 24, 'y': 19}
a
{'height': 23, 'width': 26}
如代码所示,id属性可以获取节点id,location可以获取节点在页面的相对位置,tag_name获取节点的标签名,size获取节点的大小。
总结
到这里,基本上就可以使用selenium来完成一些简单的操作了,可以获取想要的数据,快来试一试吧!