博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python 爬虫从入门到进阶之路(十)
阅读量:4591 次
发布时间:2019-06-09

本文共 6515 字,大约阅读时间需要 21 分钟。

之前的文章我们介绍了一下 Python 中正则表达式和 re 模块来做一个案例,爬取《糗事百科》的糗事并存储到本地。本章我们来看一下另一种爬取数据的方式 XPath。

我们在前面爬取《糗事百科》的时候处理 HTML 文档的时候发现会有些累人,还要对正则表达式非常熟悉爬起来才得心应手,那有没有更为方便的方法呢,答案当然是有的,我们可以先将 HTML文件 转换成 XML文档,然后用 XPath 查找 HTML 节点或元素。

什么是XML

  • XML 指可扩展标记语言(EXtensible Markup Language)
  • XML 是一种标记语言,很类似 HTML
  • XML 的设计宗旨是传输数据,而非显示数据
  • XML 的标签需要我们自行定义。
  • XML 被设计为具有自我描述性。
  • XML 是 W3C 的推荐标准

XML 和 HTML 的区别

数据格式 描述 设计目标
XML Extensible Markup Language (可扩展标记语言) 被设计为传输和存储数据,其焦点是数据的内容。
HTML HyperText Markup Language (超文本标记语言) 显示数据以及如何更好显示数据。
HTML DOM Document Object Model for HTML (文档对象模型) 通过 HTML DOM,可以访问所有的 HTML 元素,连同它们所包含的文本和属性。可以对其中的内容进行修改和删除,同时也可以创建新的元素。
XML文档示例
1 
2
3
4
this is title5
hello world6
7
HTML DOM 模型示例

HTML DOM 定义了访问和操作 HTML 文档的标准方法,以树结构方式表达 HTML 文档。

什么是XPath?

XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历。

XPath 开发工具

  1. 开源的XPath表达式编辑工具:XMLQuire(XML格式文件可用)
  2. Chrome插件 XPath Helper
  3. Firefox插件 XPath Checker

选取节点

XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。

下面列出了最常用的路径表达式:

表达式 描述
nodename 选取此节点的所有子节点。
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。

 

在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:


路径表达式
结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性。

谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中。

在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:

 

路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang=’eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

 

选取未知节点

XPath 通配符可用来选取未知的 XML 元素。

 

通配符 描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

 

路径表达式 结果
/bookstore/* 选取 bookstore 元素的所有子元素。
//* 选取文档中的所有元素。
//title[@*] 选取所有带有属性的 title 元素。

 

选取若干路径

通过在路径表达式中使用“|”运算符,您可以选取若干个路径。

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

 

路径表达式 结果
//book/title | //book/price 选取 book 元素的所有 title 和 price 元素。
//title | //price 选取文档中的所有 title 和 price 元素。
/bookstore/book/title | //price 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。

XPath的运算符

下面列出了可用在 XPath 表达式中的运算符:

 

 

这些就是XPath的语法内容,在运用到Python抓取时要先转换为xml。

lxml库

lxml 是 一个HTML/XML的解析器,主要的功能是如何解析和提取 HTML/XML 数据。

lxml和正则一样,也是用 C 实现的,是一款高性能的 Python HTML/XML 解析器,我们可以利用之前学习的XPath语法,来快速的定位特定元素以及节点信息。

lxml python 官方文档:

需要安装C语言库,可使用 pip 安装:pip install lxml (或通过wheel方式安装)

 我们利用它来解析 HTML 代码,简单示例:

1 from lxml import etree 2  3 text = ''' 4 
5
12
13 '''14 15 # 利用etree.HTML,将字符串解析为HTML文档16 html = etree.HTML(text)17 18 # 按字符串序列化HTML文档19 # html = etree.tostring(html).decode("utf8") # 不能正常显示中文20 html = etree.tostring(html, encoding="utf-8", pretty_print=True, method="html").decode("utf-8") # 可以正常显示中文21 22 print(html)

运行结果如下:

1  2 
3
12
13

lxml 可以自动修正 html 代码,例子里不仅补全了 li 标签,还添加了 body,html 标签。

文件读取:

除了直接读取字符串,lxml还支持从文件里读取内容。我们新建一个 index.html 文件:

再利用 etree.parse() 方法来读取文件。

1 from lxml import etree2 3 # 读取外部文件 hello.html4 html = etree.parse('./index.html', etree.HTMLParser())  # 指定解析器HTMLParser会根据文件修复HTML文件中缺失的如声明信息5 html = etree.tostring(html, encoding="utf-8", pretty_print=True, method="html").decode("utf-8")6 7 print(html)

运行结果:

 

接下来我们看一下 XPath 的实力测试。

1. 获取所有的 <li> 标签

1 from lxml import etree 2  3 html = etree.parse('./index.html', etree.HTMLParser()) 4 print(type(html))  # 
5 6 result = html.xpath('//li') 7 8 print(result) # [
,
,
,
,
] 9 print(len(result)) # 510 print(type(result)) #
11 print(type(result[0])) #

2. 继续获取<li> 标签的所有 class属性

1 from lxml import etree2 3 html = etree.parse('./index.html', etree.HTMLParser())4 result = html.xpath('//li/@class')5 6 print(result)  # ['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']

3. 继续获取<li>标签下hre 为 link1.html 的 <a> 标签

1 from lxml import etree2 3 html = etree.parse('./index.html', etree.HTMLParser())4 result = html.xpath('//li/a[@href="link1.html"]')5 6 print(result)  # [
]

4. 获取<li> 标签下的所有 <span> 标签

1 from lxml import etree2 3 html = etree.parse('./index.html', etree.HTMLParser())4 # result = html.xpath('//li/span')5 # 注意这么写是不对的:因为 / 是用来获取子元素的,而  并不是 
  • 的子元素,所以,要用双斜杠6 7 result = html.xpath('//li//span')8 9 print(result) # [
    ]
  • 5. 获取 <li> 标签下的<a>标签里的所有 class

    1 from lxml import etree2 3 html = etree.parse('./index.html', etree.HTMLParser())4 result = html.xpath('//li/a//@class')5 6 print(result)  # ['bold']

    6. 获取最后一个 <li> 的 <a> 的 href

    1 from lxml import etree2 3 html = etree.parse('./index.html', etree.HTMLParser())4 result = html.xpath('//li[last()]/a/@href')5 # 谓语 [last()] 可以找到最后一个元素6 7 print(result)  # ['link5.html']

    7. 获取倒数第二个元素的内容

    1 from lxml import etree2 3 html = etree.parse('./index.html', etree.HTMLParser())4 result = html.xpath('//li[last()-1]/a')5 6 # text 方法可以获取元素内容7 print(result[0].text)  # fourth item

    8. 获取 class 值为 bold 的标签名

    1 from lxml import etree2 3 html = etree.parse('./index.html', etree.HTMLParser())4 result = html.xpath('//*[@class="bold"]')5 6 # tag方法可以获取标签名7 print(result[0].tag)  # span

    XPath的更多用法参考:

    python lxml库的更多用法参考:

     

     
     

     

    转载于:https://www.cnblogs.com/weijiutao/p/10879871.html

    你可能感兴趣的文章
    html5 Canvas绘制时钟以及绘制运动的圆
    查看>>
    Unity3D热更新之LuaFramework篇[05]--Lua脚本调用c#以及如何在Lua中使用Dotween
    查看>>
    JavaScript空判断
    查看>>
    洛谷 P1439 【模板】最长公共子序列(DP,LIS?)
    查看>>
    python timeit
    查看>>
    Wireless Network 并查集
    查看>>
    51nod 1019 逆序数
    查看>>
    JavaScript面向对象编程
    查看>>
    查看IIS-7.0中的进程PID
    查看>>
    关于Python的super用法研究
    查看>>
    训练1-A
    查看>>
    ionic4+angular7+cordova上传图片
    查看>>
    [转]常用字符与ASCII代码对照表
    查看>>
    Oracle数据库提权(低权限提升至dba)
    查看>>
    再说Java集合,subList之于ArrayList
    查看>>
    Hibernate-validator校验框架使用
    查看>>
    ArcGIS Server开发教程系列(8)ArcGIS API for Javascript-控件(小部件)(续)纯代码...
    查看>>
    16.10—第三周
    查看>>
    软件工程第八次作业-例行报告
    查看>>
    算法:背包问题处理
    查看>>