前言
前面的python爬虫(1-3)讲了怎么向服务器发送请求,获得网页的源代码,不过一个网页的源代码有很多部分我们都是用不上的,那用什么方法能快速获取到我们想要的数据呢?这个时候,网页解析就派上用场了,常用的解析方法有:XPath语句、beautifulsoup4库、re正则表达式,这里先来介绍第一种。
XPath
什么是XPath
xpath(XML Path Language)是一门在 XML 和 HTML 文档中查找信息的语言,可用来在 XML和 HTML 文档中对元素和属性进行遍历。简单点说,这玩意儿就是用来帮我们提取网页源代码中我们所需要的数据的,比如标签属性值、文本值、链接等等都能通过XPath语法提取。
XPath语法的开发工具(Chrome插件)
我们想看XPath语法实时的效果,我觉得直接在浏览器里边写是最直观的方法了。谷歌浏览器的插件就帮我们解决了这个问题,插件名字叫“XPath Helper”,直接安装就行,安装步骤可以百度,教程一大把。
来看看使用,这里以豆瓣网为例子:
我先写一句做个例子(取电影汉密尔顿的豆瓣评分):
匹配好之后,我们就可以把语句复制下来粘贴到代码中。
XPath语法详解
关于XPath的语法介绍有很多,这里简单罗列:
选取节点
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从根节点选取 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
谓语
谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中。在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:
路径表达式 | 描述 |
---|---|
/bookstore/book[1] | 选取 bookstore 下的第一个子元素 |
/bookstore/book[last()] | 选取 bookstore 下的倒数第二个 book 元素。 |
bookstore/book[position()<3] | 选取 bookstore 下前面两个子元素。 |
//book[@price] | 选取拥有 price 属性的 book 元素 |
//book[@price=10] | 选取所有属性 price 等于 10 的 book 元素 |
//div[contains(@id,’1234’)] | 选取所以属性 id 中含有 1234 的 div 元素 |
通配符
通配符 | 描述 | 示例 | 结果 |
---|---|---|---|
* | 匹配任意节点 | /bookstore/* | 选取 bookstore 下的所有子元素。 |
@* | 匹配节点中的任何属性 | //book[@*] | 选取所有带有属性的 book 元素。 |
选取多个路径
通过在路径表达式中使用“|”运算符,可以选取若干个路径。示例如下:
//bookstore/book | //book/title(选取所有 book 元素以及 book 元素下所有的 title 元素)
XPath运算符
运算符 | 描述 | 实例 | 返回值 |
---|---|---|---|
| | 计算两个节点集 | //book | //cd | 返回所有拥有 book 和 cd 元素的节点集 |
+ | 加法 | 6 + 4 | 10 |
- | 减法 | 6 - 4 | 2 |
* | 乘法 | 6 * 4 | 24 |
div | 除法 | 8 div 4 | 2 |
= | 等于 | price=9.80 | 如果 price 是 9.80,则返回 true。如果 price 是 9.90,则返回false。 |
!= | 不等于 | price!=9.80 | 如果 price 是 9.90,则返回 true。如果 price 是 9.80,则返回 false。 |
< | 小于 | price<9.80 | 如果price是 9.00,则返回 true。如果 price 是 9.90,则返回 false。 |
<= | 小于或等于 | price<=9.80 | 如果 price 是 9.00,则返回 true。如果 price 是 9.90,则返回 false。 |
> | 大于 | price>9.80 | 如果 price 是 9.90,则返回 true。如果 price 是 9.80,则返回 false。 |
>= | 大于或等于 | price>=9.80 | 如果 price 是 9.90,则返回 true。如果 price 是 9.70,则返回 false。 |
or | 或 | price=9.80 orprice=9.70 | 如果 price 是 9.80,则返回 true。如果 price 是 9.50,则返回 false。 |
and | 与 | price>9.00 andprice<9.90 | 如果 price 是 9.80,则返回 true。如果 price 是 8.50,则返回 false。 |
mod | 计算除法的余数 | 5 mod 2 | 1 |
lxml
什么是lxml
lxml 是 一个 HTML/XML 的解析器,主要的功能是如何解析和提取 HTML/XML 数据。lxml 和正则一样,也是用 C 实现的,是一款高性能的 Python HTML/XML 解析器,我们可以利用之前学习的 XPath 语法,来快速的定位特定元素以及节点信息。这里附上官方文档
先来说一个坑
我们一般使用lxml库里的etree方法,我第一次使用lxml库的时候被坑的蛮惨,由于我装的是版本较新的lxml库(4.4.1),老版本的导入方法是from lxml import etree
,嗯,果不其然报错了。然后就是去找答案,最后发现在比较新的版本里,etree被封装到lxml下的html库里边了,所以可以这样导入:
from lxml import html
etree = html.etree
大致流程
使用requests库和lxml库进行爬虫一般分为以下几个步骤:
导库,设置请求头,利用requests库向网页发送请求,并得到一个response对象
利用etree对response对象进行解析,得到一个lxml.etree._Element对象,该对象可以使用xpath语法进行提取信息
利用xpath语法对lxml.etree._Element对象进行信息提取
将提取的信息进行处理
实例
这里利用requests库和lxml库来爬取豆瓣网经典的电影排名前10的电影信息:
导入相关模块:
import requests from lxml import html etree = html.etree
设置一些参数
headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " "(KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36" }#请求头 url = "https://movie.douban.com/chart"#目标链接 movies = []#用于保存电影信息
requests库请求
# 向指定页数发起请求,并返回resopnse对象 response = requests.get(url, headers=headers)
etree对response对象进行解析
html = etree.HTML(response.text) tables = html.xpath("//table")
用xpath提取信息并保存
for table in tables: detail_herf = table.xpath('.//a[@class="nbg"]/@href')[0] name = table.xpath(".//a[@class='nbg']/@title")[0] post_url = table.xpath(".//img/@src")[0] nums = table.xpath(".//span[@class='rating_nums']/text()")[0] movie ={ "href": detail_herf,#详情链接 "name": name,#电影名 "post_url": post_url,#海报链接 "nums": nums#评分 } print(movie) movies.append(movie)
运行,结果如下图:
最后,再贴一下完整代码:# 爬取豆瓣电影经典影片排名 import requests from lxml import html etree = html.etree headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " "(KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36" } url = "https://movie.douban.com/chart" movies = [] n = 1 # 向指定页数发起请求,并返回resopnse对象 response = requests.get(url, headers=headers) html = etree.HTML(response.text) tables = html.xpath("//table") for table in tables: #这个地方可以借助前面介绍的谷歌浏览器插件来检查匹配是否正确 detail_herf = table.xpath('.//a[@class="nbg"]/@href')[0] name = table.xpath(".//a[@class='nbg']/@title")[0] post_url = table.xpath(".//img/@src")[0] nums = table.xpath(".//span[@class='rating_nums']/text()")[0] movie = { "href": detail_herf, "name": name, "post_url": post_url, "nums": nums } print(movie) movies.append(movie)
总结一下
嗯,总的看来,写个小爬虫其实是很简单的,xpath语法也很好理解,但仅掌握这些是不够的,无法写出很diao的爬虫,还有蛮多东西要学习!