AJAX(Asynchronouse JavaScript And XML)异步JavaScript和XML,在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。传统的网页(不使用Ajax)如果需要更新内容,必须重载整个网页页面。
因为传统的在传输数据格式方面,使用的是XML语法,因此叫做AJAX,其实现在数据交互基本上都是使用JSON,很少使用XML了。
使用AJAX加载的数据,即使执行了JS代码 将数据渲染到了浏览器中,在右键-查看网页源代码还是不能看到通过ajax加载的数据。
查看源代码看到的是服务器最原始的HTML,不包含ajax生成的HTML元素。
如下图:可以看到页面中引入了很多js文件和css文件,这些文件有的是用来动态生成元素的,有的是其他用途。反正除了这些文件路径和一些JavaScript代码,在页面中获取不到任何有用的网页信息。
而审查元素则可以看到生成的各种HTML元素,这些元素都是浏览器通过对引入的js和css进行解析生成的,生成这些元素使用的是ajax技术。
如下图:
1、直接分析ajax调用的接口,然后通过代码请求这个接口,俗称怼加密(找加密、网页js逆向),需要很强的前端 JavaScript功底。
优点:直接可以请求到数据,不需要做一些解析工作,代码量少,性能高
缺点:分析接口比较复杂,特别是一些通过js混淆的接口,要有一定的js功底;容易被发现是爬虫
2、使用Selenium+chromedriver模拟浏览器行为获取数据,使用代码模拟人工操作,用代码控制浏览器,得到的数据是和审查元素一样的,也就是说浏览器上能看到的都能得到。
优点:直接模拟浏览器的行为,浏览器能请求到的,使用selenium也能请求到;爬虫更稳定
缺点:代码量多,性能低
一般在post请求的时候,比如注册或登陆时,提交数据经常是加密的(一般密码会进行加密),这种都是需要找出加密方法,并且在post请求的时候模拟出加密数据。
随着慢慢普及,现在js逆向几乎每个人都会一些,只是有些js混淆的厉害,着实难搞。
Selenium相当于是一个机器人,可以模拟人类在浏览器上的一些行为,自动处理浏览器上的一些行为,比如点击,填充数据,删除cookie等。
chromedriver是一个驱动Chrome浏览器的驱动程序,使用它才可以驱动浏览器。
当然,针对不同的浏览器有不同的driver。
Chrome:https://sites.google.com/a/chromium.org/chromedriver/downloads
Firefox:https://github.com/mozilla/geckodriver/releases
Edge:https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
Safari:https://webkit.org/blog/6900/webdriver-support-in-safari-10/
安装Selenium:
Selenium有很多语言的版本,java、ruby、python等。
python版本安装:
pip install selenium
安装chromedriver:
通过上面的地址,下载完成后,放到不需要权限的纯英文目录下就可以了。
一个获取百度首页的例子
from selenium import webdriver
# chromedriver所在的绝对路径
driver_path = r'D:\ProgramApp\chromedriver\chromedriver.exe'
# 使用webdriver.Chrome初始化一个对象(driver),并且指定chromedriver的路径
driver = webdriver.Chrome(executable_path=driver_path)
driver.get("https://www.baidu.com/") # 请求网页
print(driver.page_source) # 通过page_source获取网页源代码
更多教程请参考:http://selenium-python.readthedocs.io/installation.html#introduction
driver.close():关闭当前页面
driver.quit():退出整个浏览器
1、根据id查找元素
submitTag = driver.find_element_by_id('su')
# 另一种方式
from selenium.webdriver.common.by import By # 导入By模块
submitTag1 = driver.find_element(By.ID,'su')
2、根据类名查找元素
submitTag = driver.find_element_by_class_name('su')
# 另一种方式
from selenium.webdriver.common.by import By # 导入By模块
submitTag1 = driver.find_element(By.CLASS_NAME,'su')
3、根据name属性的值查找元素
submitTag = driver.find_element_by_name('email')
# 另一种方式
from selenium.webdriver.common.by import By # 导入By模块
submitTag1 = driver.find_element(By.NAME,'email')
4、根据标签名查找元素
submitTag = driver.find_element_by_tag_name('div')
# 另一种方式
from selenium.webdriver.common.by import By # 导入By模块
submitTag1 = driver.find_element(By.TAG_NAME,'div')
5、根据xpath语法获取元素
submitTag = driver.find_element_by_xpath('//div')
# 另一种方式
from selenium.webdriver.common.by import By # 导入By模块
submitTag1 = driver.find_element(By.XPATH,'//div')
6、根据css选择器选择元素
submitTag = driver.find_element_by_css_selector('.quickdelete-wrap > input')
# 另一种方式
from selenium.webdriver.common.by import By # 导入By模块
submitTag1 = driver.find_element(By.CSS_SELECTOR,'.quickdelete-wrap > input')
注意:
find_element是获取第一个满足条件的元素
find_elements是获取所有满足条件的元素,返回列表
如果只是解析获取网页中的数据,可使用driver.page_source获取网页HTML源代码,再将网页代码用lxml解析,因为lxml底层是用c语言执行的,效率高。
而且使用这种方式,只需要打开一次页面获取到HTML源代码后就可以了,使用selenium获取元素的方法有时候还获取不到文本和标签属性的值(使用xpath中的 /text()、/@属性 的时候)。
使用driver.page_source获取网页HTML源代码后,还可以使用正则、bs4等其他方法解析数据。
如果需要对网页中的一些元素进行一些操作,如:给文本框输入内容、点击按钮等,就必须使用selenium提供的查找元素方法来操作。
常见的表单元素(更多可自行学习HTML知识):
input标签:
文本框:type=“text”/“password”/“email”/“number” ---- typed等于这些的都属于文本框
text 是普通文本框,password是密码输入框,number是数字
button(按钮):input type=“submit” ---- button也属于input标签,typed=“submit”
checkbox(选择框):input type=“checkbox” ---- checkbox也属于input标签,type=“checkbox”
select(下拉列表)
1、 操作输入框:
第一步:找到元素
第二步:使用send_keys(value),将数据填充进去
inputTag = driver.find_element_by_id('kw')
inputTag.send_keys('python')
# 使用clear方法可以清除输入框中的内容
inputTag.clear()
2、操作checkbox:
因为要选中checkbox标签,在网页中是通过鼠标左键点击的,所以先选中这个标签,再执行click事件
rememberTag = driver.find_element_by_name("rememberMe")
rememberTag.click()
rememberBth.click() # 再点一次取消选中选择框
3、选择select:
select元素不能直接点击,因为点击后还需要选中元素,这时候selenium就专门为select标签提供了一个类selenium.webdriver.support.ui.Select
将获取到的元素当成参数传到这个类中,创建这个对象,以后就可以使用这个对象进行选择了
from selenium.webdriver.support.ui import Select
# 选中这个标签,然后使用Select创建对象
selectTag = Select(driver.find_element_by_id('jk'))
selectTag.select_by_index(1) # 根据索引选择
selectTag.select_by_value("value属性的值") # 根据value值选择
selectTag.select_by_visible_text("标签中的文本") # 根据可视的文本选择
selectTag.deselect_all() # 取消选中所有选项
4、操作按钮 button:
操作按钮有很多种方式,比如单击、右击、双击等。最常用的就是点击,直接调用click方法就可以了
inputTag = driver.find_element_by_id('su')
inputTag.click()
按钮单击跟选择框一样都使用.click()
行为链
有时候在页面中的操作可能要有很多步,这时可以使用鼠标行为链类ActionChains来完成。比如现在要将鼠标移动到某个元素上并执行点击事件。
from selenium.webdriver.common.action_chains import ActionChains
driver.get('https://www.baidu.com') # 模拟打开百度页面
inputTag = driver.find_element_by_id('kw') # 获取到百度输入框
submitTag = driver.find_element_by_id('su') # 获取到百度一下按钮
# 选中这两个元素后再进行下面的行为链ActionChains操作
actions = ActionChains(driver) # 创建行为链对象,把driver传进去
actions.move_to_element(inputTag) # 把鼠标移动到inputTag标签上
actions.send_keys_to_element(inputTag,'python') # 给inputTag发送数据(要搜索的关键词:‘python’)
actions.move_to_element(submitTag) # 再把鼠标移动到submitBth标签上
actions.click(submitTag) # 点击submitBth按钮
actions.perform() # 停止行为
更多的鼠标相关的操作
click_and_hold(element):点击但不松开鼠标。
context_click(element):右键点击。
double_click(element):双击。
更多方法请参考:http://selenium-python.readthedocs.io/api.html
获取所有的cookie:
for cookie in driver.get_cookies():
print(cookie)
根据cookie的key获取value:
value = driver.get_cookie(key)
删除所有的cookie:
driver.delete_all_cookies()
删除某个cookie:
driver.delete_cookie(key)
driver.delete_cookie('PSTM')
print(driver.get_cookie('PSTM')) # 删除后就获取不到这条cookie了,返回None
现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出来了。如果实际页面等待时间过长导致某个dom元素还没出来,但代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。
为了解决这个问题,所以 Selenium 提供了两种等待方式:一种是隐式等待、一种是显式等待。
1、隐式等待:调用driver.implicitly_wait。这时在获取元素之前,会先等待
在创建driver时,为浏览器对象创建一个最长等待时间,这个方法是得不到某个元素就等待,直到浏览器所有元素加载完毕(左上角的圈圈不在转了)、拿到元素位置(如果一直拿不到就等到时间截止),再执行下一步
隐式等待是全局的,设置一次后,所有的元素在加载的时候都会等待,会在那死等,等不到(超时)就抛出异常然后继续执行后面的代码
driver.implicitly_wait(10) # 10秒
# 请求网页
driver.get("https://www.douban.com")
driver.find_element_by_id('lalala')
# 输入一个错误的id,不设置等待的话会立马抛出异常,设置等待会等待后抛出异常
2、显示等待:显示等待是明确表明某个条件成立后才执行获取元素的操作,可以在等待的时候指定一个最大的时间,如果超过这个时间就抛出一个异常
显示等待应该使用selenium.webdriver.support.excepted_conditions期望的条件和selenium.webdriver.support.ui.WebDriverWait来配合完成
显式等待是根据条件来判断,条件满足就不等了,条件一直不满足就一直等待到超时并抛出异常
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
——driver:WebDriver 的驱动程序(Ie, Firefox, Chrome 或远程)
——timeout:最长超时时间,默认以秒为单位
——poll_frequency:休眠时间的间隔(步长)时间,默认为 0.5 秒
——ignored_exceptions:超时后的异常信息,默认情况下抛 NoSuchElementException 异常
WebDriverWait(driver, 10).until(
lambda driver: driver.findElement(By.Id("someId"))) # 用这种方式也可以指定期望的条件
# 每隔0.5秒扫描一次检查是否有id为someId的元素,10秒后没找到就不找了抛异常
from selenium.webdriver.common.by import By # 另一种获取元素的方法 By类
from selenium.webdriver.support.ui import WebDriverWait # WebDriverWait 显示等待的类
from selenium.webdriver.support import expected_conditions as EC # 期望条件,太长了所以一般取别名为EC
try:
element = WebDriverWait(driver, 10).until( # 传入driver和最大等待时间
EC.presence_of_element_located((By.ID, 'form_email')) # 期望的条件(By.ID, 'form_email')
)
finally:
driver.quit()
期望的条件只能传递一个参数,所以两个参数要放元组里
.presence_of_element_located():判断某个元素是否存在当前页面
有form_email这个id表示条件满足,说明要寻找的页面的元素已经加载出来了
更多等待条件:
presence_of_element_located:某个元素已经加载完毕了
presence_of_all_emement_located:网页中所有满足条件的元素都加载完毕了
element_to_be_cliable:某个元素是可以点击了
更多条件请参考:http://selenium-python.readthedocs.io/waits.html
有时候窗口中有很多子tab页面,这时肯定是需要进行切换的
selenium提供了driver.execute_script(“window.open(‘url’)”)方法来打开一个新的tab页面
driver.switch_to_window()方法来进行切换,具体切换到哪个页面,可以用driver.window_handles()来实现
# 打开一个新的页面
driver.execute_script("window.open('url')")
# 切换到这个新的页面中
driver.switch_to_window(driver.window_handles[1])
from selenium import webdriver
driver_path = r'D:\PycharmProjects\chromedriver\chromedriver.exe'
# 定义chromedriver.exe所在的绝对路径
driver = webdriver.Chrome(executable_path=driver_path)
# 使用webdriver.Chrome初始化一个对象(driver),驱动的是Chrome浏览器,指定上面创建路径。
driver.get('https://www.baidu.com') # 模拟打开百度页面
# driver.get('https://www.douban.com')
# 模拟打开豆瓣网页面,用这种方式打开多个网址都是在浏览器的一个tab标签页面下的,所以会覆盖前面打开的页面
# 打开一个新的页面
driver.execute_script("window.open('https://www.douban.com')") # window.open是js里面的方法
print(driver.current_url)
# 虽然在新的tab标签页面下打开了豆瓣网页,但是driver当前所在页面url还是百度
# 如果想要在代码中切换到某个页面并做一些爬虫操作,就需要用到.switch_to_window()来进行切换
# 通过.window_handles取出具体第几个窗口
# .window_handles是一个列表,里面放的是窗口句柄,按照窗口打开时候的顺序进行并排序的
# 切换到这个新的页面中
print(driver.window_handles) # 查看当前打开的浏览器所有的标签页面窗口句柄
driver.switch_to_window(driver.window_handles[1]) # 切换tab页面
print(driver.current_url) # 现在的url是豆瓣的了
# print(driver.page_source) # 通过page_source获取网页源代码。打印出来的是豆瓣的页面HTML代码
driver.switch_to.window(driver.window_handles[0])
print(driver.current_url) # 现在的url又是百度的了
.switch_to_window()是老版本,被废弃了,会提现下面的错误,但是不影响运行
DeprecationWarning: use driver.switch_to.window instead
self.driver.switch_to_window(self.driver.window_handles[1])
新的版本:.switch_to.window()
有时候频繁爬取一些网页,服务器发现你是爬虫后会封掉你的ip地址,这时候我们可以更改代理ip
更改代理ip,不同的浏览器有不同的实现方式,这里仅以Chrome浏览器为例
from selenium import webdriver
driver_path = r'D:\PycharmProjects\chromedriver\chromedriver.exe'
options = webdriver.ChromeOptions() # .ChromeOptions类是设置Chrome浏览器一些请求信息的
options.add_argument('--proxy-server=http://27.203.219.181:8118') # 在请求信息里设置代理服务器ip
driver = webdriver.Chrome(executable_path=driver_path, chrome_options=options)
# 使用webdriver.Chrome初始化一个对象,指定上面创建路径和代理ip
driver.get('http://httpbin.org/ip')
WebElement元素
from selenium.webdriver.remote.webelement import WebElement类是每个获取出来的元素的所属类
有一些常用的方法 属性:
1、get_attribute():这个标签的某个属性的值
2、screentshot():获取当前页面的截图,这个方法只能在driver上使用
driver的对象类,也是继承自WebElement
更多请阅读相关文档或源代码
from selenium import webdriver
driver_path = r'D:\PycharmProjects\chromedriver\chromedriver.exe'
# 定义chromedriver.exe所在的绝对路径
driver = webdriver.Chrome(executable_path=driver_path)
# 使用webdriver.Chrome初始化一个对象(driver),指定上面创建路径。
driver.get('https://www.baidu.com') # 模拟打开页面
submitBth = driver.find_element_by_id('su') # 获取到百度一下按钮
print(type(submitBth)) # 类型:
# 通过这个类型可以进行一系列的操作(获取到标签、属性及属性所对应的值,字符串等等...)
print(submitBth.get_attribute('value')) # 获取到value属性所对应的值:'百度一下'四个字
driver.save_screenshot(r'C:\Users\Administrator\Desktop\baidu.png') # 截图保存整个网页
相关文档:
selenium异常处理:
https://selenium-python.readthedocs.io/api.html#module-selenium.common.exceptions
selenium中文翻译文档:https://selenium-python-zh.readthedocs.io/en/latest
ChromeDriver下载镜像:
https://npm.taobao.org/mirrors/chromedriver
http://chromedriver.storage.googleapis.com/index.html
以上内容是看网易云的21天学会分布式爬虫时整理的笔记和自己平时积累的一些小东西
拓展:
https://www.cnblogs.com/pyspark/p/8195896.html