python爬虫(4)——XPath语法和lxml


前言

前面的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库进行爬虫一般分为以下几个步骤:

  1. 导库,设置请求头,利用requests库向网页发送请求,并得到一个response对象

  2. 利用etree对response对象进行解析,得到一个lxml.etree._Element对象,该对象可以使用xpath语法进行提取信息

  3. 利用xpath语法对lxml.etree._Element对象进行信息提取

  4. 将提取的信息进行处理

    实例

    这里利用requests库和lxml库来爬取豆瓣网经典的电影排名前10的电影信息:

  5. 导入相关模块:

    import requests
    from lxml import html
    etree = html.etree
    
  6. 设置一些参数

    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 = []#用于保存电影信息
    
  7. requests库请求

    # 向指定页数发起请求,并返回resopnse对象
    response = requests.get(url, headers=headers)
    
  8. etree对response对象进行解析

    html = etree.HTML(response.text)
    tables = html.xpath("//table")
    
  9. 用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的爬虫,还有蛮多东西要学习!


文章作者: Reset Ran
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Reset Ran !
  目录