一文搞定强大的爬虫数据解析工具-Xpath

强大的Xpath

之前爬虫解析数据的时候,自己几乎都是用正则表达式。正则解析数据很强大,但是表达式写起来很麻烦,速度相对较慢。本文介绍的是如何快速入门一种数据解析工具:Xpath。

image

Xpath介绍

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

XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。

  • Xpath是一种查询语言
  • 在XML(Extensible Markup Language)和HTML的树状结构中寻找节点
  • XPATH是一种根据‘地址’来‘寻找人’的语言

快速入门网站:https://www.w3schools.com/xml/default.asp

Xpath安装

MacOS中安装非常的简单:

pip install lxml

Linux中的安装以Ubuntu为例:

sudo apt-get install python-lxml

Windows中的安装请自行百度,肯定会有教程的,就是过程相对会比较麻烦些。

如何检验安装是否成功?命令行中import lxml没有报错,即表示安装成功!

image

Xpath解析原理

  • 实例化一个etree解析对象,且需要将解析的页面源码数据加载到对象中
  • 调用xpath中的xpath解析方法结合着xpath表达式实现标签的定位和内容的捕获

如何实例化etree对象?

  1. 将本地的html文档中的源码数据加载到etree对象中:etree.parse(filePath)
  2. 将互联网上获取的源码数据加载到该对象中:etree.HTML('page_text'),其中page_text指的就是我们获取到的源码内容

Xpath使用方法

3个特殊符号

  • /:表示从根节点开始解析,并且是单个层级,逐步定位
  • //:表示多个层级,可以跳过其中的部分层级;也表示从任意位置开始定位
  • .:一个点表示当前的节点

常见路径表达式

下面是常见的Xpath路径表达式:

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

举例

image
表达式 说明
books 选取 books 元素的所有子节点
/books 选取根元素 bookstore
books//title 选取属于 books 的子元素的所有 title 元素
//price 选取所有 price 元素
books/book[3] 选取属于 books 子元素的第3个 book 元素,索引从1开始
/bookstore/book[price>55.0] 选取所有单价大于55的 book 元素
//@category 选取所有名为 category 的属性
/books/book/title/text() 选取文档所有 title 值

Xpath运算符

在Xpath表达式式中是直接支持运算符的:

image
Operator Description Example Chinese
| Computes two node-sets //book | //cd 合并两个结果
+ Addition 6 + 4
- Subtraction 6 - 4
* Multiplication 6 * 4
div Division 8 div 4
= Equal price=9.80 等于
!= Not equal price!=9.80 不等于
< Less than price<9.80 小于
<= Less than or equal to price<=9.80 小于等于
> Greater than price>9.80 大于
>= Greater than or equal to price>=9.80 大于等于
or or price=9.80 or price=9.70
and and price>9.00 and price<9.90
mod Modulus (division remainder) 5 mod 2 求余

HTML元素

HTML 元素指的是从开始标签(start tag)到结束标签(end tag)的所有代码。基本语法:

  • HTML 元素以开始标签起始;HTML 元素以结束标签终止
  • 元素的内容是开始标签与结束标签之间的内容
  • 某些 HTML 元素具有空内容(empty content)
  • 空元素在开始标签中进行关闭(以开始标签的结束而结束)
  • 大多数 HTML 元素可拥有属性;属性推荐使用小写

关于空元素的使用:在开始标签中添加斜杠,比如<br />,是关闭空元素的正确方法,HTML、XHTML 和 XML 都接受这种方式。

常见属性

image
属性 描述
class classname 规定元素的类名(classname)
id id 规定元素的唯一 id
style style_definition 规定元素的行内样式(inline style)
title text 规定元素的额外信息(可在工具提示中显示)

HTML标题

HTML中标题共有6级。

标题(Heading)是通过 <h1> - <h6> 等标签进行定义的。

<h1> 定义最大的标题,<h6> 定义最小的标题。

原数据

使用Xpath解析数据之前,我们需要先导入库,同时实例化一个etree对象:

# 导入库
from lxml import etree

# 实例化解析对象
tree = etree.parse("test.html")
tree

下面是待解析的原数据test.html:

  1 <html lang="en">
  2 <head>
  3     <meta charset="UTF-8" />
  4     <title>古代诗人及作品</title>
  5 </head>
  6 <body>
  7     <div>
  8         <p>诗人姓名</p>
  9     </div>
 10     <div class="name">
 11         <p>李白</p>
 12         <p>白居易</p>
 13         <p>李清照</p>
 14         <p>杜甫</p>
 15         <p>王安石</p>
 16         <a href="http://wwww.tang.com" title="李世民" target="_self">
 17             <span> this is span </span>
 18         古代诗人写的诗词真的非常棒</a>
 19         <a href="" class="du">床前明月光,疑是地上霜</a>
 20         <img src="http://www.baidu.com/tang.jpg" alt="" />
 21     </div>
 22     <div class="tang">
 23         <ul>
 24             <li><a href="http://www.baidu.com" title="百度">朝辞白帝彩云间,千里江陵一日还</a></li>
 25             <li><a href="http://www.sougou.com" title="搜狗">清明时节雨纷纷,路上行人欲断魂</a></li>
 26             <li><a href="http://www.360.com" alt="360">秦时明月汉时关,万里长征人未还</a></li>
 27             <li><a href="http://www.sina.com" title="必应">君子赠人以言,庶人赠人以财</a></li>
 28             <li><b>苏轼</b></li>
 29             <li><i>苏洵</i></li>
 30             <li><a href="http://www.google.cn" id="谷歌">欢迎使用谷歌浏览器</a></li>
 31         </ul>
 32     </div>
 33 </body>
 34 </html>                     
image

获取单个标签内容

比如想获取title标签中的内容:古代诗人及作品

image
title = tree.xpath("/html/head/title")
title
image

通过上面的结果发现:每个Xpath解析的结果都是一个列表

如果想取得标签中的文本内容,使用text():

# 从列表中提取相应内容

title = tree.xpath("/html/head/title/text()")[0]  # 索引0表示取得第一个元素值
title
image

获取标签内的多个内容

比如我们想获取div标签的内容,原数据中有3对div标签,结果是列表中含有3个元素:

image

1、使用单斜线/:表示根节点html开始定位,表示的是一个层级

image

2、中间使用双斜线//:表示跳过中间的层级,表示的是多个层级

image

3、开头部位使用双斜线//:表示从任意位置开始

image

属性定位

使用属性定位的时候直接在标签后面跟上[@属性名="属性值"]

image
name = tree.xpath('//div[@class="name"]')   # 定位class属性,值为name
name
image

索引定位

Xpath中索引是从1开始,和python中的索引从0开始是不同的。比如想定位div标签下class属性(值为name)下的全部p标签:5对p标签,结果应该是5个元素

image
# 获取全部数据

index = tree.xpath('//div[@class="name"]/p')
index
image

如果我们想获取其中的第3个p标签:

# 获取单个指定数据:索引从1开始

index = tree.xpath('//div[@class="name"]/p[3]')  # 索引从1开始
index
image

获取文本内容

第一种方法:text()方法

1、获取具体某个标签下面的元素:

# 1、/:单个层级
class_text = tree.xpath('//div[@class="tang"]/ul/li/b/text()')
class_text
# 2、//:多个层级
class_text = tree.xpath('//div[@class="tang"]//b/text()')
class_text
image

2、某个标签下面的多个内容

image

比如想获取p标签下面的全部内容:

# 获取全部数据

p_text = tree.xpath('//div[@class="name"]/p/text()')
p_text
image

比如想获取第3个p标签下面的内容:

# 获取第3个标签内容

p_text = tree.xpath('//div[@class="name"]/p[3]/text()')  
p_text
image

如果是先获取p标签中的全部内容,结果是列表,再使用python索引获取,注意索引为2:

image

非标签直系内容的获取:

image

标签直系内容的获取:结果为空,直系的li标签中没有任何内容

image

如果想获取li标签的全部内容,可以将下面的a、b、i标签合并起来,使用竖线|

image
# 同时获取li标签下面a/b/i标签的内容,相当于是li标签全部的内容

abi_text = tree.xpath('//div[@class="tang"]//li/a/text() | //div[@class="tang"]//li/b/text() | //div[@class="tang"]//li/i/text()')
abi_text
image

直系和非直系理解

image

取属性内容

如果想获取属性的值,在最后的表达式中加上:@+属性名,即可取出相应属性的值

1、获取单个属性的值

image
image

2、获取属性的多个值

image
image

总结

在这里对Xpath的使用总结下:

  • //:表示获取标签非直系内容,有跨越层级
  • /:表示只获取标签的直系内容,不跨越层级
  • 如果索引是在Xpath表达式中,索引从1开始;如果从Xpath表达式中获取到列表数据后,再使用python索引取数,索引从0开始

实战

利用XPATH来爬取小说网站上古龙的全部小说名称(name)和URL地址(url),古龙简介:

本名熊耀华,江西人;台湾淡江英专(即淡江大学前身)毕业(一说肄业)。少年时期便嗜读古今武侠小说及西洋文学作品,一般多以为他是受到吉川英治、大小仲马、海明威、杰克伦敦、史坦贝克小说乃至尼采、沙特等西洋哲学的影响启迪。 (古龙自己也说过“我喜欢从近代日本及西洋小说‘偷招’。”) 故能日新又新,後来居上,且别开武侠小说新境界。

网页数据分析

爬取的信息在这个网站上:https://www.kanunu8.com/zj/10867.html

image

当我们点击具体某个小说,比如“绝代双骄”就可以进去该小说的具体信息中:

image

通过查看网页的源码,我们发现名称和URL地址全部在下面的标签中:

image

每个tr标签下面有3个td标签,代表3个小说,一个td包含地址和名称

image

获取网页源码

发送网页请求获取到源码

import requests
from lxml import etree 
import pandas as pd

url = 'https://www.kanunu8.com/zj/10867.html'
headers = {'user-agent': '请求头'}

response = requests.get(url = url,headers = headers)
result = response.content.decode('gbk')   # 该网页需要通过gbk编码来解析数据
result 
image

获取信息

1、获取每个小说的专属链接地址

tree = etree.HTML(result)

href_list = tree.xpath('//tbody/tr//a/@href')  # 指定属性的信息
href_list[:5]
image

2、获取每个小说的名称

name_list = tree.xpath('//tbody/tr//a/text()')  # 指定标签下面的全部内容
name_list[:5]
image

3、生成数据帧DataFrame

# 生成古龙小说的地址和名称

gulong = pd.DataFrame({
    "name":name_list,
    "url":href_list 
})

gulong
image

4、完善URL地址

实际上每个小说的URL地址是有一个前缀的,比如绝代双骄的完整地址:https://www.kanunu8.com/book/4573/

gulong['url'] = 'https://www.kanunu8.com/book' + gulong['url']   # 加上公共前缀
gulong

# 导出为excel文件
gulong.to_excel("gulong.xlsx",index=False)
image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容