Python3爬虫——用Xpath提取网页信息

Posted 甲寅Emore

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python3爬虫——用Xpath提取网页信息相关的知识,希望对你有一定的参考价值。

Python3爬虫——用Xpath提取网页信息

前言

本笔记用于记录整理requests库的一些基本知识,内容会根据博主自己的认知作增添或压缩。
水平有限,如有错误请不吝赐教。
本文需要读者初步了解html有关节点的相关知识。


文章目录

Xpath的梗概和安装

XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。使用Xpath最初是用于搜寻XML文档的,但同样适用于HTML文档的搜索。

使用Xpath前,请先保证其已经安装,可以利用pip进行安装:

pip3 install lxml

这里主要用到lxml包内的etree的库,其提供了Xpath的方法。

Xpath常用规则

表达式描述
nodename选取此节点的所有子节点
/进入当前节点的直接子节点
//进入当前节点的子孙节点
.选取当前节点
..选取当前节点的父节点
@选取当前节点的属性

小试牛刀:

//title[@endtime="2023-02-04"]

意思是选取所有名为title并带有属性endtime"2023-02-04"的节点

使用Xpath

接入HTML文本

从内存中读取

假设已经存在这样一段HTML文本:

text = '''
<div class="device-notification">
  <a class="device-notification--logo" href="#0">
    <img src="assets/img/logo.png" alt="Global">
    <p>Emoreの云</p>
  </a>
  <p class="device-notification--message">请将手机横向放置以继续体验</p>
</div>
'''

这意味着这段HTML存在内存内,可能是网上抓取来的或是提前读取好的,接入Xpath的方法如下:

import lxml import etree  # 载入etree库

html = etree.HTML(text)  # 构造Xpath解析对象

从文件中读取

假设有一个text.html文件在你的程序所在的文件夹中,里面这需要解析的HTML文本:

from lxml import etree  # 载入etree库

html = etree.parse('./text.html', etree.HTMLParser())  # 从文本构造Xpath解析对象

不论是哪种方法构造Xpath解析对象,etree都会对HTML文本进行修正。如果从文件读取,修正时可能额外出现DOCTYPE声明。

查找节点

所有节点

利用Xpath查找结点时,一般采用以//开头的Xpath规则选择所有符合要求的节点。以上文的HTML文本为例:

>>> html = etree.HTML(text)
>>> result1 = html.xpath('//*')  # *代表选择当前目录的所有节点
>>> print(result1)  # 返回结果是列表
[<Element html at 0x27378d2c440>, <Element body at 0x27378e98140>, <Element div at 0x27378e98300>, <Element a at 0x27378e98400>, <Element img at 0x27378e98440>, <Element p at 0x27378e98480>, <Element p at 0x27378e98240>]

>>> print(result1[0])  # 选取结果中的第一个
<Element html at 0x27378d2c440>

其中Element后面的内容便是节点名,本身不存在的html节点和body节点都自动补全了。

指定节点

//后面的内容换成节点名,即可查找指定节点,如查询上文所有的p节点:

>>> result2 = html.xpath('//p')
>>> print(result2)
[<Element p at 0x27378e98480>, <Element p at 0x27378e98240>]

同时可以查询具有指定属性的p节点,只需要在节点名后面附带筛选属性,利用[@]将其包裹起来:

>>> result3 = html.xpath('//p[@class="device-notification--message"]')
>>> print(result3)
[<Element p at 0x27378e98240>]

如此只返回了最后一个p节点。

属性多值匹配

有的属性不止有一个值(上文HTML并没有这种情况),需要用contains()方法进行匹配。该方法第一个参数为属性名,第二个参数填入属性值,只要拥有该属性值的节点都会被返回。

result = html.xpath('//p[contains(@class, "device-notification--message")]')
多属性匹配

需要通过多个属性匹配一个节点,可以利用and进行连接,比如匹配一个class含有值device并且nameEmorep节点:

result = html.xpath('//p[contains(@class, "device") and @name="Emore"]')  # 仅举例

除了and,Xpath还含有很多运算符(摘自菜鸟编程),

运算符描述实例返回值
|计算两个节点集//book | //cd返回所有拥有 book 和 cd 元素的节点集
+加法6 + 410
-减法6 - 42
*乘法6 * 424
div除法8 div 42
=等于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。
orprice=9.80 or price=9.70如果 price 是 9.80,则返回 true。如果 price 是 9.50,则返回 false。
andprice>9.00 and price<9.90如果 price 是 9.80,则返回 true。如果 price 是 8.50,则返回 false。
mod计算除法的余数5 mod 21
选择顺序

有时候有两个或者多个节点,可以像列表一样选择其中某个节点。需要注意的是,Xpath是从1开始计数的。

# 仅举例
result = html.xpath('//div/p[0]')  # 选择第一个p节点
result = html.xpath('//div/p[last()]')  # 选择最后一个p节点
result = html.xpath('//div/p[posision()<3]')  # 选择前面两个p节点
result = html.xpath('//div/p[last()-2]')  # 选择倒数第三个p节点 

查找子孙节点

查找子孙节点只需要像文件路径一样/下去就好了,不同的是/是只访问直接子节点,而//是访问所有的子孙节点:

例如我需要寻找div节点下的p节点:

>>> result4 = html.xpath('//div/p')  # 利用'/'搜索节点p
>>> result5 = html.xpath('//div//p')  # 利用'//'搜索节点p
>>> print(result4)
[<Element p at 0x27378e98240>]

>>> print(result5)
[<Element p at 0x27378e98480>, <Element p at 0x27378e98240>]

div节点的直接子节点中含有一个p节点,还有一个a节点。其中a节点内含有一个img节点和一个p节点。利用/只检索到一个p节点,而利用//检索到了两个p节点,即访问了子节点和孙节点。

查找父节点

同样类似命令cd ..打开上级目录,Xpath中的..可以用于进入父节点。

>>> result6 = html.xpath('//div/p/../a/img')
>>> print(result6)
[<Element img at 0x27378e98440>]

首先进入了div节点的p节点,然后从p节点返回绕到了a节点,并取得里面的img节点。

获得属性和文本

利用Xpath内的text()方法可以获得节点的文本,利用@可以获得指定属性的值。

>>> print(result7)
['请将手机横向放置以继续体验']

>>> result8 = html.xpath('//div/p/@class')
>>> print(result8)
['device-notification--message']

同样输出为列表。

节点轴选择

通过轴节点可以快速选择具有相关关系的节点,如选择div节点的所有直接子节点:

>>> result10 = html.xpath('//div/child::*')
>>> print(result10)
[<Element a at 0x27378e98400>, <Element p at 0x27378e98240>]

首先需要调用child轴,获得所有匹配的节点,然后使用两个冒号::进入选择器,接着用*选择所有节点。

还有很多轴可供选择(摘自菜鸟编程):

轴名称结果
ancestor选取当前节点的所有先辈(父、祖父等)。
ancestor-or-self选取当前节点的所有先辈(父、祖父等)以及当前节点本身。
attribute选取当前节点的所有属性。
child选取当前节点的所有子元素。
descendant选取当前节点的所有后代元素(子、孙等)。
descendant-or-self选取当前节点的所有后代元素(子、孙等)以及当前节点本身。
following选取文档中当前节点的结束标签之后的所有节点。
following-sibling选取当前节点之后的所有兄弟节点
namespace选取当前节点的所有命名空间节点。
parent选取当前节点的父节点。
preceding选取文档中当前节点的开始标签之前的所有节点。
preceding-sibling选取当前节点之前的所有同级节点。
self选取当前节点。

小结

使用XPath可以快速而准确地进行HTML节点选择,并提取信息,但是要注意构造XPath表达式,以避免提取错误。

同时还有一些需要注意的地方:

  • 顺序选择节点时,起始数为1
  • 选择文本的时候需要精准地进入节点,否则text()会返回错误的文本,如一个换行符或一个缩进。

python爬虫零基础实战

content

1.什么是爬虫?

2.为什么用python做网页爬虫

3.python环境配置

4.我需要了解哪些python爬虫的前置知识

5.关于正则表达式

6.提取网页内容并用正则表达式处理

7.xPath和BeautifulSoup工具简介

 

 

1.爬虫简介

简单来讲,爬虫就是一个探测机器,它的基本操作就是模拟人的行为去各个网站溜达,点点按钮,查查数据,或者把看到的信息背回来。就像一只虫子在一幢楼里不知疲倦地爬来爬去。

你可以简单地想象:每个爬虫都是你的“分身”。就像孙悟空拔了一撮汗毛,吹出一堆猴子一样。

你每天使用的百度,其实就是利用了这种爬虫技术:每天放出无数爬虫到各个网站,把他们的信息抓回来,然后化好淡妆排着小队等你来检索。
抢票软件,就相当于撒出去无数个分身,每一个分身都帮助你不断刷新 12306 网站的火车余票。一旦发现有票,就马上拍下来,然后对你喊:土豪快来付款。
--摘自知乎用户 史中
  互联网就像一张网,中间以各种链接连接在一起,而小小的爬虫却能在这张网上欢快的驰骋,代替人来进行很多繁重的任务,如抢票软件、某度搜索引擎。
 
 
 
2.为什么用python做网页爬虫
  python作为一门易上手的语言,提供了丰富的API来抓取网页文档、模拟浏览器行为、对抓取到的数据进行处理。后面我们的演示中也会展示python爬虫的简介,爬取网页内容的核心代码可能只有短短几行,却能实现强大的功能。
 
 
3.python环境配置
  对于新手来说,最熟悉的还是windows环境。我使用的是anaconda+pycharm进行python代码的编写,这里anaconda方便进行外部库的管理,而pycharm也是功能强大很流行的一款IDE。详细的配置过程参见博客:     anaconda和pycharm的安装与配置 。
 
4.我需要了解哪些python爬虫的前置知识
  至少会一点python的基础知识,如果不清楚的话,可以参加浙大翁恺的python慕课,或者自己找些介绍文档,如       python入门教程。同时需要了解关于html的一些基础知识,比如各种标签代表的含义:

<!–…–>:定义注释
<!DOCTYPE> :定义文档类型
<html>:html文档的总标签
<head>:定义头部
<body>:定义网页内容
<script>:定义脚本
<div>:division,定义分区,容器标签
<p>:paragraph,定义段落
<a>:定义超链接
<span>:定义文本容器
<br>:换行
<form>:定义表单
<table>:定义表格
<th>:定义表头
<tr>:表的行
<td>:表的列
<b>:定义粗体字
<img>:定义图片

  熟悉上面这些html标签将会方便我们进行正则表达式的处理,以及xPath和BeautifulSoup的学习。
 
5. 关于正则表达式
 
  python正则表达式相关知识较多,我们只需要了解一些基础的即可,如:
 
6.提取网页内容并用正则表达式处理
 
  
import re
import urllib.request
import chardet

response=urllib.request.urlopen("http://news.hit.edu.cn/")#输入参数为你想爬取的网页URL

html=response.read() #读取到html变量中
chardet1=chardet.detect(html) #获取编码方式
html=html.decode(chardet1[\'encoding\']) #按照获取到的编码方式进行处理

   这里我们以某高校的官方新闻网站为例演示来进行python爬虫操作,上面短短的几行代码就实现了将网页内容爬取到本地的操作。

  接着就是对爬取到的内容进行正则表达式处理,得到我们想要获取的内容,观察网页源代码:

  

我们希望对其中的外部链接进行匹配,由之前了解到的正则表达式知识,实现如下:

mypatten="<li class=\\"link-item\\"><a href=\\"(.*)\\"><span>(.*)</span></a></li>"
mylist=re.findall(mypatten,html)
for i in mylist:
    print("外部链接地址:%s 网站名:%s" %(i[0],i[1]))

最后得到的效果是:

 

7.xPath和BeautifulSoup工具简介

  除了用正则表达式处理得到的网页文档之外,我们还可以考虑网页自身的架构。

XPath,全称 XML Path Language,即 XML 路径语言,它是一门在XML文档中查找信息的语言。XPath 最初设计是用来搜寻XML文档的,但是它同样适用于 HTML 文档的搜索。

  nodename选取此节点的所有子节点
  /从当前节点选取直接子节点
  //从当前节点选取子孙节点
  .选取当前节点
  ..选取当前节点的父节点
  @选取属性

  在这里列出了XPath的常用匹配规则,例如 / 代表选取直接子节点,// 代表选择所有子孙节点,. 代表选取当前节点,.. 代表选取当前节点的父节点,@ 则是加了属性的限定,选取匹配属性的特定节点。

from lxml import etree
import urllib.request
import chardet
response=urllib.request.urlopen("https://www.dahe.cn")

html=response.read()
chardet1=chardet.detect(html)
html=html.decode(chardet1[\'encoding\'])
etreehtml=etree.HTML(html)
mylist=etreehtml.xpath("/html/body/div/div/div/div/div/ul/div/li")

BeautifulSoup4是爬虫必学的技能。BeautifulSoup最主要的功能是从网页抓取数据,Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。BeautifulSoup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它,则 Python 会使用 Python默认的解析器,lxml 解析器更加强大,速度更快,推荐使用lxml 解析器。

from bs4 import BeautifulSoup 
file = open(\'./aa.html\', \'rb\') 
html = file.read() 
bs = BeautifulSoup(html,"html.parser") # 缩进格式
print(bs.prettify()) # 格式化html结构
print(bs.title) # 获取title标签的名称
print(bs.title.name) # 获取title标签的文本内容
print(bs.title.string) # 获取head标签的所有内容
print(bs.head) # 获取第一个div标签中的所有内容
print(bs.div) # 获取第一个div标签的id的值
print(bs.div["id"]) # 获取第一个a标签中的所有内容
print(bs.a) # 获取所有的a标签中的所有内容
print(bs.find_all("a")) # 获取id="u1"
print(bs.find(id="u1")) # 获取所有的a标签,并遍历打印a标签中的href的值
for item in bs.find_all("a"): 
    print(item.get("href")) # 获取所有的a标签,并遍历打印a标签的文本值
for item in bs.find_all("a"): 
    print(item.get_text())

 

以上是关于Python3爬虫——用Xpath提取网页信息的主要内容,如果未能解决你的问题,请参考以下文章

什么是网络爬虫技术?

Python爬虫--Xpath

python爬虫基础04-网页解析库xpath

1.Scrapy爬虫之静态网页爬取之一 了解response.xpath()

Python爬虫爬取糗事百科(xpath+re)

Python3 爬虫XPath Helper的安装与使用