1、AJAX描述
AJAX(Asynchronouse JavaScript And XML)异步JavaScript和XML,在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新,这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。传统的网页(不使用Ajax)如果需要更新内容,就必须重载整个网页页面,因为传统的在传输数据格式方面,使用的是XML语法,因此叫做AJAX,其实现在数据交互基本上都是使用JSON。使用Ajax加载的数据,即使使用了JS,将数据渲染到了浏览器中,在“右键->查看网页源代码”还是不能看到通过Ajax加载的数据,只能看到使用这个url加载的html代码。
2、获取Ajax数据的方式
1)直接分析Ajax调用的接口,然后通过代码请求这个接口。
2)使用Selenium + chromedriver模拟浏览器行为获取数据。
方式 | 优点 | 缺点 |
---|---|---|
分析接口 | 直接可以请求到数据, 不需要做一些解析工作。 代码量少,性能高 |
分析接口比较复杂, 特别是一些通过js混淆的接口, 要有一定的js功底, 容易被发现是爬虫。 |
Selenium | 直接模拟浏览器的行为, 浏览器能请求到的, 使用Selenium也能请求到, 爬虫更稳定 |
代码量多,性能低 |
3、Selenium + chromedriver获取动态数据
Selenium相当于是一个机器人,可以模拟人类在浏览器上的一些行为,自动处理浏览器上的一些行为,比如点击、填充数据、删除cookie等。
chromedriver是一个驱动Chrome浏览器的驱动程序,使用他才可以驱动浏览器,当然针对不同的浏览器有不同的driver,以下列出了不同浏览器机器对应的driver:
a)Chrome:https://sites.google.com/a/chromium.org/chromedriver/downloads
b)Firefox:https://github.com/mozilla/geckodriver/releases
c)Edge:https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
d)Safari:https://webkit.org/blog/6900/webdriver-support-in-safari-10/
1)安装Selenium和chromedriver
a)安装Selenium:Selenium有很多语言的版本,有Java、Ruby、Python等。
b)安装chromedriver:下载完成后,放到不需要权限的纯英文目录下就可以了。
2)快速入门
现在以一个简单的获取百度首页的例子来快速入门Selenium和chromedriver:
from selenium import webdriver
# chromedriver的绝对路径
driver_path = r"D:\chromedriver\chromedriver.exe"
# 初始化一个driver,并且指定chromedriver的路径
driver = webdriver.Chrome(executable_path=driver_path)
# 请求网页
driver.get('https://www.baidu.com')
# 通过page_source获取网页源代码
print(driver.page_source)
运行结果:自动打开Chrome浏览器如下图所示,并且打印出网页源代码。

3)Selenium常用操作
更多教程请参考:http://selenium-python.readthedocs.io/installation.html#introduction
A)关闭页面
A.1)driver.close():关闭当前页面
A.2)driver.quit():退出整个浏览器
from selenium import webdriver
import time
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
time.sleep(5)
driver.close()
time.sleep(5)
driver.quit()
B)定位元素
注:find_element是获取第一个满足条件的元素,find_elements是获取所有满足条件的元素。
B.1)find_element_by_id:根据id来查找元素,等价于:
submitTag = driver.find_element_by_id('su')
submitTag1 = driver.find_element(By.ID, 'su')
示例代码(1)如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_element_by_id('kw')
inputTag.send_keys('python')
示例代码(2)如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_element(By.ID, 'kw')
inputTag.send_keys('python')
B.2)find_element_by_class_name:根据类名查找元素,等价于:
submitTag = driver.find_element_by_class_name('su')
submitTag1 = driver.find_element(By.CLASS_NAME, 'su)
示例代码如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_element_by_class_name('s_ipt')
inputTag.send_keys('python')
B.3)find_element_by_name:根据name属性的值来查找元素,等价于:
submitTag = driver.find_element_by_name('email')
submitTag1 = driver.find_element(By.NAME, 'email')
示例代码如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_element_by_name('wd')
inputTag.send_keys('python')
B.4)find_element_by_tag_name:根据标签名来查找元素,等价于:
submitTag = driver.find_element_by_tag_name('div')
submitTag1 = driver.find_element(By.TAG_NAME,'div')
B.5)find_element_by_xpath:根据xpath语法来获取元素,等价于:
submitTag = driver.find_element_by_xpath('//div')
submitTag1 = driver.find_element(By.XPATH, '//div')
示例代码如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_element_by_xpath("//input[@id='kw']")
inputTag.send_keys('python')
B.6)find_element_by_css_selector:根据css选择器选择元素,等价于:
submitTag = driver.find_element_by_css_selector('//div')
submitTag1 = driver.find_element(By.CSS_SELECTOR, '//div')
示例代码(1)如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_element_by_css_selector(".quickdelete-wrap > input")
inputTag.send_keys('python')
示例代码(2)如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_elements_by_css_selector(".quickdelete-wrap > input")[0]
inputTag.send_keys('python')
C)操作表单元素
C.1)常用表单元素
input:type = 'text/password/email/number'
button、input:type = 'submit'
checkbox:type = 'checkbox'
select:下拉列表
C.2)操作输入框:分为两步,第一步:找到这个元素,第二步:使用send_keys(value)
将数据填充进去,示例代码如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_element_by_id('kw')
inputTag.send_keys('python')
使用clear
方法可以清楚输入框中的内容,示例代码如下:
from selenium import webdriver
import time
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_element_by_id('kw')
inputTag.send_keys('python')
time.sleep(3)
inputTag.clear()
C.3)操作checkbox:因为要选中checkbox
标签,在网页中是通过鼠标点击的,因此想要选中checkbox
标签,先选中这个标签,然后执行click
事件,示例代码如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.douban.com')
elementi = driver.find_element_by_tag_name('iframe') # 定位到iframe
driver.switch_to.frame(elementi) # 切入iframe
rememberBtn = driver.find_element_by_name('remember')
rememberBtn.click()
C.4)操作select:select
元素不能直接点击,因为点击后还需要选中元素,这时候selenium
就专门为select
标签提供了一个类selenium.webdriver.support.ui.Select
,将获取到的元素当成参数传到这个类中,创建这个对象,以后就可以使用这个对象进行选择了,示例代码如下:
from selenium import webdriver
from selenium.webdriver.support.ui import Select
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('http://xianyang06360.11467.com/')
selectBtn = Select(driver.find_element_by_name('nsid')) # 选中这个标签,然后使用Select创建对象
# selectBtn.select_by_index(1) # 根据索引选择
# selectBtn.select_by_value('2') # 根据值选择
selectBtn.select_by_visible_text('产品') # 根据可视的文本选择
# selectBtn.deselect_all() # 取消选中所有选项
C.5)操作按钮:操作按钮有很多种方式,比如单击、右击、双击等,这里只讲最常用的单击,直接调用click
函数就可以,示例代码如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_element_by_id('kw')
inputTag.send_keys('python')
clickBtn = driver.find_element_by_id('su')
clickBtn.click()
D)操作行为链
有时候在页面中的操作可能要有很多步,那么这时候可以使用鼠标行为链类ActionChains
来完成,比如现在要将鼠标移动到某个元素上并执行点击事件,示例代码如下:
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
inputTag = driver.find_element_by_id('kw')
submitTag = driver.find_element_by_id('su')
actions = ActionChains(driver)
actions.move_to_element(inputTag)
actions.send_keys_to_element(inputTag, 'python')
actions.move_to_element(submitTag)
actions.click(submitTag)
actions.perform()
还有更多的鼠标相关的操作:
a)click_and_hold(element):点击但不松开鼠标
b)context_click(element):右键点击
c)double_click(element):双击
更多方法请参考:http://selenium-python.readthedocs.io/api.html
E)操作Cookie
E.1)获取所有的cookie
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
for cookie in driver.get_cookies():
print(cookie)
运行结果:
{'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '30973_1449_31118_21086_31187_30824_26350_31164_31195'}
{'domain': '.baidu.com', 'expiry': 1618558602.689842, 'httpOnly': False, 'name': 'BAIDUID', 'path': '/', 'secure': False, 'value': 'A5F0BE95DD1F26F0AA75AB29BD2F7285:FG=1'}
{'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'BD_HOME', 'path': '/', 'secure': False, 'value': '1'}
{'domain': '.baidu.com', 'expiry': 3734506249.689763, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1587022603'}
{'domain': 'www.baidu.com', 'expiry': 1587886603, 'httpOnly': False, 'name': 'BD_UPN', 'path': '/', 'secure': False, 'value': '12314753'}
{'domain': '.baidu.com', 'expiry': 3734506249.689632, 'httpOnly': False, 'name': 'BIDUPSID', 'path': '/', 'secure': False, 'value': 'A5F0BE95DD1F26F0CF89F6000DA5C1D6'}
E.2)根据cookie的key获取value
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
for cookie in driver.get_cookies():
print(cookie)
print('-' * 100)
print(driver.get_cookie('PSTM'))
运行结果:
{'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '30969_1447_31169_21090_31217_30824_31163_22158'}
{'domain': '.baidu.com', 'expiry': 1618558826.5253, 'httpOnly': False, 'name': 'BAIDUID', 'path': '/', 'secure': False, 'value': 'CCD56BC52CA0797650FF41F1DE8C7A07:FG=1'}
{'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'BD_HOME', 'path': '/', 'secure': False, 'value': '1'}
{'domain': '.baidu.com', 'expiry': 3734506473.52528, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1587022827'}
{'domain': 'www.baidu.com', 'expiry': 1587886827, 'httpOnly': False, 'name': 'BD_UPN', 'path': '/', 'secure': False, 'value': '12314753'}
{'domain': '.baidu.com', 'expiry': 3734506473.525246, 'httpOnly': False, 'name': 'BIDUPSID', 'path': '/', 'secure': False, 'value': 'CCD56BC52CA079760E777777C96D8FFC'}
====================================================================================================
{'domain': '.baidu.com', 'expiry': 3734506473.52528, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1587022827'}
E.3)删除某个cookie
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
print(driver.get_cookie('PSTM'))
driver.delete_cookie('PSTM')
print('-' * 100)
print(driver.get_cookie('PSTM'))
运行结果:
{'domain': '.baidu.com', 'expiry': 3734506620.415989, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1587022974'}
----------------------------------------------------------------------------------------------------
None
E.4)删除所有的cookie
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
for cookie in driver.get_cookies():
print(cookie)
print('-' * 100)
driver.delete_all_cookies()
print('-' * 100)
for cookie in driver.get_cookies():
print(cookie)
运行结果:
{'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '30971_1456_21108_31229_30823_31164'}
{'domain': '.baidu.com', 'expiry': 1618559078.01659, 'httpOnly': False, 'name': 'BAIDUID', 'path': '/', 'secure': False, 'value': '2816B00D030A93B74E6FC721AC4A617C:FG=1'}
{'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'BD_HOME', 'path': '/', 'secure': False, 'value': '1'}
{'domain': '.baidu.com', 'expiry': 3734506725.016538, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1587023079'}
{'domain': 'www.baidu.com', 'expiry': 1587887078, 'httpOnly': False, 'name': 'BD_UPN', 'path': '/', 'secure': False, 'value': '12314753'}
{'domain': '.baidu.com', 'expiry': 3734506725.016481, 'httpOnly': False, 'name': 'BIDUPSID', 'path': '/', 'secure': False, 'value': '2816B00D030A93B7890B7B46FAE224A6'}
----------------------------------------------------------------------------------------------------
F)页面等待
现在的网页越来越多采用了Ajax技术,这样程序便不能确定何时某个元素完全加载出来了,如果实际页面等待时间过长导致某个dom元素还没有出来,但是你的代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。为了解决这个问题,Selenium提供了两种等待方式:一种是隐式等待,一种是显式等待。
F1)隐式等待:调用deriver.implicitly_wait
,在获取不可用的元素之前,会先等待10秒钟的时间,示例代码如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.douban.com')
driver.implicitly_wait(10)
driver.find_element_by_id('lkjlkjl')
运行结果:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="lkjlkjl"]"}
(Session info: chrome=81.0.4044.9)
F2)显式等待:显式等待是表明某个条件成立后才执行获取元素的操作,也可以在等待的时候指定一个最大的时间,如果超过这个时间就抛出一个异常,显式等待应该使用selenium.webdriver.support.excepted_conditions
期望的条件和selenium.webdriver.support.ui.WebDriverWait
来配合完成。
示例代码(1)如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.douban.com')
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, 'lkjlkj'))
)
finally:
driver.quit()
运行结果:
selenium.common.exceptions.TimeoutException: Message:
示例代码(2)如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.douban.com')
elementi = driver.find_element_by_tag_name('iframe') # 定位到iframe
driver.switch_to.frame(elementi) # 切入iframe
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, 'phone'))
)
finally:
driver.quit()
print(element)
运行结果:
<selenium.webdriver.remote.webelement.WebElement (session="72ffcfd184c6457786fb6b428aa09d88", element="43714d55-52a5-4772-8566-485fe50acda8")>
F.3)其他的一些等待条件:
a)presence_of_element_located
:某个元素已经加载完毕了。
b)presence_of_all_element_located
:网页中所有满足条件的元素都加载完毕了。
c)element_to_be_cliable
:某个元素是可以点击了。
更多条件请参考:http://selenium-python.readthedocs.io/waits.html
G)切换页面
有时候窗口中有很多子tab页面,这时候肯定是需要进行切换的,selenium
提供了switch_to_window
来进行切换,具体切换到哪个页面,可以从driver.window_handles
中找到,示例代码如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
# driver.get('https://www.douban.com')
driver.execute_script("window.open('https://www.douban.com')") # 打开一个新的页面
print(driver.window_handles)
print('切换之前的网页是{}'.format(driver.current_url))
driver.switch_to.window(driver.window_handles[1]) # 切换到新的页面中
print('切换之后的网页是{}'.format(driver.current_url))
运行结果:
['CDwindow-7AC07DE61FD21770433360D8416CA254', 'CDwindow-9904C78191603F1D626361548A8E9930']
切换之前的网页是https://www.baidu.com/
切换之后的网页是https://www.douban.com/
虽然在窗口中切换到了新的页面,但是driver中还没有切换,如果想要在代码中切换到新的页面,并且做一些爬虫,那么应该使用driver.swtich_to_window
来切换到指定的窗口。从driver.window_handlers
中取出具体第几个窗口。driver.window_handlers
是一个列表,里面装的都是窗口句柄,会按照打开页面的顺序来存储窗口的句柄。
H)设置代理IP
有时候频繁爬取一些网页,服务器发现你是爬虫后悔封掉你的IP地址,这时候我们可以更改代理IP。更改代理IP,不同的浏览器有不同的方式,这里以Chrome
浏览器为例,示例代码如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
options = webdriver.ChromeOptions()
options.add_argument('--proxy-server=http://171.35.167.190:9999')
driver = webdriver.Chrome(executable_path=driver_path, options=options)
driver.get('http://httpbin.org/ip')
I)WebElement元素
from selenium.webdriver.remote.webelement import WebElement
类是每个获取出来的元素的所属类.
一些常用的属性:
a)get_attribute
:这个标签的某个属性的值。
b)screenshot
:获取当前页面的截图,这个方法只能在driver
上使用,driver
的对象类,也是继承自WebElement
。
更多请阅读相关源代码。
示例代码如下:
from selenium import webdriver
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
submitBtn = driver.find_element_by_id('su')
print(type(submitBtn))
print(submitBtn.get_attribute('value'))
driver.save_screenshot('baidu.png')
运行结果:
<class 'selenium.webdriver.remote.webelement.WebElement'>
百度一下
4、Selenium、chromedriver和lxml结合使用
A)如果只是想要解析网页中的数据,那么推荐将网页源代码扔给lxml来解析,因为lxml底层使用的是C语言,所以解析效率会更高。
B)如果是想要对元素进行一些操作,比如给一个文本框输入值,或者是点击某个按钮,那么就必须使用selenium给我们提供的查找元素的方法。
示例代码如下:
from selenium import webdriver
from lxml import etree
driver_path = r"D:\chromedriver\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get('https://www.baidu.com')
html = etree.HTML(driver.page_source)
title = html.xpath('//div[@id="lg"]//map//@title')
print(title)
网友评论