目录
Python lxml 模块
lxml.etree
XPath
lxml 扩展知识
Python requests 模块
requests.get() 方法
响应对象的属性与方法
会话对象
SSL 证书验证,客户端证书,CA 证书
代理
Cookie
提高场景
Python selenium 入手篇
selenium 安装
编写第一个 selenium 案例
webdriver 对浏览器基本操作
网页元素定位
通过 ID 与 name 进行定位
通过 XPath 表达式进行定位
selenium 入手篇扩展知识
安装 PhanomJS
使用无头浏览器
lxml
库是一款 Python 数据解析库,参考重要文档在 lxml - Processing XML and HTML with Python,
在解析数据的时候,大量的代码都是基于 Element
对象的 API 实现。
在爬虫代码采集过程中,通过 etree.HTML
直接将字符串实例化为 element
对象。
import requests
from lxml import etree
res = requests.get("http://www.jsons.cn/zt/")
html = res.text
root_element = etree.HTML(html)
print(root_element)#
print(root_element.tag)#html
其中需要注意的是 Element 后面的 html,该字符串表示对象的标签名为 html
,如果使用下述代码:
print(root_element[0])
上述内容得到的是
print("*"*100)
for child in root_element:
print(child.tag)#head 表示在 html 标签中,只包含head 标签
也可以通过 etree.tostring(element对象)
直接将该对象转换为字符串进行输出。
for child in root_element:
for item in child:
print(item.tag)
print(etree.tostring(item))
lxml 库可以配合其他的解析引擎进行工作,首次接触的就是 XPath
,
在爬虫代码编写中,直接使用 html.xpath("xpath表达式")
即可获取目标数据,例如获取网页 title。
print(root_element.xpath('//title'))
获取网页所有文本:
print(root_element.xpath('string()'))
获取到 element 对象之后,可调用 text
属性,获取对应文本,在使用的时候,需要注意使用 XPath
获取到的 element 对象,都是列表。
title_element = root_element.xpath('//title')
print(title_element[0].text)
在 lxml
中,还内置了一款 简单的类似 XPath 的路径语言,称为 ElementPath
,例如查询 title,需要从 head
开始检索,否则返回 None
。
print(root_element[0].find("title"))
官方提供的方法如下:
iterfind()
: 返回查找到的数据,迭代器形式返回;findall()
: 返回匹配到的列表;find()
: 返回第一个匹配到的数据;findtext()
: 返回匹配到的文本数据,第一个。正则表达式 与 XPath 语法领域细解,初学阶段的你,该怎么学?
lxml
除了可以配合 XPath
实现数据解析外,还可以与 cssselect
,BeautifulSoup
,html5lib
配合使用,这部分在后续的案例中,将逐步进行展开。
lxml
在爬虫领域,更多的是在提取数据,因此较于该库本身,掌握 XPath
等解析表达式的写法更加重要。
Python 爬虫或网络请求时,最先接触的第三方库就是 requests
,requests
库提供了中文手册 - https://docs.python-requests.org/zh_CN/latest/
。
requests.get()
方法除 url 参数外,其余都为可选参数,即非必选。
url
:请求地址;params
:要发送的查询字符串,可以为字典,列表,元组,字节;data
:body 对象中要传递的参数,可以为字段,列表,元组,字节或者文件对象;json
:JSON 序列化对象;headers
:请求头,字典格式;cookies
:传递 cookie,字段或 CookieJar
类型;files
:最复杂的一个参数,一般出现在 POST
请求中,格式举例 "name":文件对象
或者 {'name':文件对象}
,还可以在一个请求中发送多个文件,不过一般爬虫场景不会用到;auth
:指定身份验证机制;timeout
:服务器等待响应时间,在源码中检索到可以为元组类型,这个之前没有使用过,即 (connect timeout, read timeout)
;allow_redirects
:是否允许重定向;proxies
:代理;verify
:SSL 验证;stream
:流式请求,主要对接流式 API;cert
:证书。除了 GET
请求外,requests
还内置了其他的服务器请求方式GET
, OPTIONS
, HEAD
, POST
, PUT
, PATCH
, DELETE
这些方法需要的参数与上述清单一致。
在 Python 爬虫的实战当中,主要以 GET
与 POST
为主,
常用的参数为:url
,params
,data
,headers
,cookies
,timeout
,proxies
,verify
。
使用 requests
库请求之后,会得到一个 Response
对象,掌握该对象的技巧就是了解其属性与方法,通过 dir()
函数可以获取 Response
对象的属性和方法。
help(res)
print(dir(res))
获取到的内容如下所示,其中有我们之前案例中常见的一些内容。
['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__', '__dir__', '其余内容自行查询']
如果只将 requests
库应用在爬虫采集领域,那上述属性与方法中,比较常用的有:
属性 property
ok
:只要状态码 status_code
小于 400,都会返回 True;is_redirect
:重定向属性;content
:响应内容,字节类型;text
:响应内容,Unicode 类型;status_code
:响应状态码;url
:响应的最终 URL 位置;encoding
:当访问 r.text
时的编码;方法
json()
:将响应结果序列化为 JSON; requests 存在的
高级特性,即会话对象,会话对象可以保持参数。
该对象能够在跨域请求的时候,保持住某些参数,尤其是 cookie
,如果你想向同一主机发送多个请求,使用会话对象可以将底层的 TCP 连接进行重用,从而带来显著的性能提升。
会话对象使用非常简单,在发起 requests
对象之前,增加如下所示代码即可。
# 建立会话对象
s = requests.Session()
# 后续都使用会话对象进行进行,而不是直接使用 requests 对象
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get("http://httpbin.org/cookies")
print(r.text)
会话也可用来为请求方法提供缺省数据,顾名思义就是直接给会话对象增加的请求参数,
import requests
s = requests.Session()
s.auth = ('user', 'pass')
s.headers.update({'x-test': 'true'})
# both 'x-test' and 'x-test2' are sent
r = s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
print(r.text)
方法级别的参数也不会被跨请求保持,即在 s.get()
方法中如果传递了 cookie
,那不会被保持住。
通过会话对象的属性设置的参数,能被保持,而通过会话对象方法传递的参数,不能被保持。
在爬虫采集数据的过程中,碰到 https
的网站在正常不过,requests
库使用过程中 SSL 验证是默认开启的,如果证书验证失败,即抛出 SSLError
错误。
不过在实战的时候,我们可以通过设置 verify = False
,忽略对 SSL 证书的验证。
部分场景无法忽略证书,必须增加相关证书逻辑。
有的网站在采集过程中,会针对 IP 进行限制,此时就需要使用代理进行跳过操作,设置 proxies
参数即可,
除了 HTTP 代理外, requests 2.10
版本之后,增加了 SOCKS
代理,如果你需要使用,需要通过 pip
安装相应库。
pip install requests[socks]
安装完毕,出现新的第三方库 PySocks
,使用方式与 HTTP 代理一致。
爬虫采集过程会大量的与 cookie
打交道,获取网站响应的 cookie
,使用 response
对象的 cookies
属性即可。
如果希望向服务器传递 cookie
,可以通过 cookies
参数,例如下述代码:
url = 'http://httpbin.org/cookies'
cookies = dict(cookies_are='working')
r = requests.get(url, cookies=cookies)
如果你希望对 cookie
有更加细致的操作,重点研究 requests.cookies.RequestsCookieJar
对象即可,
简单的代码使用如下所示:
jar = requests.cookies.RequestsCookieJar()
jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')
jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')
url = 'http://httpbin.org/cookies'
r = requests.get(url, cookies=jar)
print(r.text)
RequestsCookieJar
对象具备更加丰富的接口,适合跨域名跨路径使用,相关接口可在 https://docs.python-requests.org/zh_CN/latest/api.html#requests.cookies.RequestsCookieJar 查询。
requests
非常适合作为 Python 爬虫入门阶段第一选择,其简单的接口与代码封装,能大幅度降低网络请求代码编写难度,让你专注与目标数据的提取,更有基于高级请求的封装作为提高部分,该库完全可以贯穿你的整个爬虫工程师生涯。
学习基本使用之后,可以使用 requests
模块实现一些简易爬虫案例,例如参考《Python 爬虫小课》,全部都是基于 requests 模块完成。
requests
模块目前在 Python 爬虫领域的出场率极高,很多简单的接口开发,也会基于它进行实现,
因此,该模块十分重要,需要牢牢掌握
selenium 项目最早是为测试浏览器、网页开发的,并且广泛应用于爬虫,需要注意 selenium
不是单个软件,它其实由一系列的工具组成。
selenium 与 webdriver 是两个项目, webdriver 是对 selenium 的二次开发,selenium 存在三个大版本,关系如下所示:
selenium1.0 + webdriver = selenium2.0
使用命令 pip install selenium
即可安装 selenium
库,安装完毕直接通过 import selenium
测试即可。
接下来还需要下载一个 WebDriver
,它用于驱动浏览器运行。
chrome 浏览器 的 WebDriver(chromedriver.exe),可以在下述地址下载:
CNPM Binaries Mirror
firefox 浏览器的 WebDriver(geckodriver.exe),可以在下述地址下载:
https://github.com/mozilla/geckodriver/releases
其他浏览器驱动:
Edge:https://developer.microsoft.com/en-us/micrsosft-edage/tools/webdriver
Safari:WebDriver Support in Safari 10 | WebKit
下载文件之后,解压到一个固定目录,记住该地址,需要在环境变量中进行配置。
G:\chromedriver_win32
测试配置是否正确:
from selenium import webdriver
driver = webdriver.Chrome()
运行代码出现谷歌浏览器,表示安装完成。
使用 selenium
打开百度首页。
from selenium import webdriver
driver = webdriver.Chrome()
# 设置浏览器大小
driver.set_window_size(800,600)
# 可以直接最大化
driver.maximize_window()
# 打开百度
driver.get("http://www.baidu.com")
基本操作包括:
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.maximize_window() # 最大化浏览器窗口
driver.get("http://www.baidu.com") # 打开百度
time.sleep(1) # 暂停1秒钟
driver.get("https://www.csdn.net/") # 打开 CSDN 首页
time.sleep(1) # 暂停1秒钟
driver.back() # 回退
time.sleep(1) # 暂停1秒钟
driver.forward() # 前进
time.sleep(1) # 暂停1秒钟
driver.refresh() # 页面刷新
time.sleep(1) # 暂停1秒钟
driver.quit() # 浏览器关闭
元素定位需要 HTML 基础支持,这部分内容直接百度学习即可,selenium 提供了 8 种网页元素定位方式,分别如下:
find_element_by_id()
和 find_elements_by_id()
;find_element_by_class_name()
和 find_elements_by_class_name()
;find_element_by_tag_name()
和 find_elements_by_tag_name()
;find_element_by_css_selector()
和 find_elements_by_css_selector()
;find_element_by_name()
和 find_elements_by_name()
;find_element_by_xpath()
和 find_elements_by_xpath()
;find_element_by_link_text()
和 find_elements_by_link_text()
;find_element_by_partial_link_text()
和 find_elements_by_partial_link_text()
。其中返回
element
表示单数(第一个),返回elements
表示复数,得到全部。
接下来用 简书 jianshu.com 首页,完成定位测试。
from selenium import webdriver
driver = webdriver.Chrome()
driver.maximize_window() # 最大化浏览器窗口
driver.get("http://www.jianshu.com") # 打开简书
driver.find_element_by_id("q").send_keys("梦想橡皮擦") # 通过ID检索搜索框,并输入文本
driver.find_element_by_class_name("search-btn").click() # 通过 class name 搜索按钮,并点击
这里调用方法出现了一个问题,解决方式如下:
关于新版本selenium定位元素报错:‘WebDriver‘ object has no attribute ‘find_element_by_id‘等问题
代码中的
send_keys()
表示想目标元素输入数据,click()
表示点击操作查看元素各种属性依赖浏览器的开发者工具,这些都属于前端知识,大家可以针对性的补充。
XPath 定位重点要学习的是 XPath 语句的写法,可以参考:正则表达式 与 XPath 语法领域细解,初学阶段的你,该怎么学?_梦想橡皮擦的博客-CSDN博客_xpath和正则表达式 进行学习。
通过 class(类)名进行定位
注意该定位方式不支持复合类名,例如 ,无法使用
driver.find_element_by_class_name("nav navbar-nav")
进行获取,仅支持单独的 class
名称。
其余获取元素的方式基本雷同,一般情况下使用 ID 和 class(类)名获取元素场景比较多。
仅作为扩展知识,最新版本的 selenium 已经不支持 PhanomJS
PhanomJS 是一款隐形浏览器(无界面 / 无头浏览器),主要用于自动化测试,网络爬虫,网络监控等领域。
下载与安装非常简单,打开国内镜像网站下载即可,一般不要下载 beta 版本。
https://npm.taobao.org/mirrors/phantomjs
解压文件,获取 bin 目录完整路径,填写到环境变量中。
配置完毕,在控制台输入 phantomjs -v
查看程序对应版本。
由于谷歌和火狐浏览器都推出了无头浏览器,所以 selenium 弃用了 PhantomJS,使用 Chrome 无头浏览器的方式为:
from selenium import webdriver
opt = webdriver.ChromeOptions() # 创建 chrome 参数对象
opt.headless = True # 设置无头浏览器
driver = webdriver.Chrome(options=opt) # 创建 chrome 无界面对象
driver.get("http://www.jianshu.com") # 打开简书
title = driver.title
print("网页标题是:", title)
driver.save_screenshot("./jianshu.png")#保存截图
有的博客在设置无头浏览器时,会使用如下函数:opt.set_headless()
,不过在最新版本中也已经被废弃,使用 opt.headless
即可。
还可以编写如下代码:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
opt = Options() # 创建 chrome 参数对象
opt.add_argument('-headless') # 无头参数
driver = webdriver.Chrome(options=opt) # 创建 chrome 无界面对象
driver.get("http://www.jianshu.com") # 打开简书
title = driver.title
print("网页标题是:", title)
driver.save_screenshot("./jianshu.png")
selenium 退出有两种方式:
driver.close()
:不会清除临时文件夹中的 WebDriver 临时文件;driver.quit()
:删除临时文件夹。表象的理解 close
与 quit
的区别是,close
关闭浏览器当前标签,quit
关闭浏览器。