版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27283619/article/details/89150774
Day 5【Datawhale】爬虫入门学习——学习XPath
1 学习XPath
1.1 什么是XPath
XPath全称XML Path Language,即XML路径语言。XPath主要使用在XML文档中选择节点,同时XPath也适用于HTML。
- XPath 使用路径表达式在 XML 文档中进行导航
- XPath 包含一个标准函数库
- XPath 是 XSLT 中的主要元素
- XPath 是一个 W3C 标准
1.2 节点及节点的关系
- 节点
在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。XML 文档是被作为节点树来对待的。树的根被称为文档节点或者根节点。 - 节点关系
这个跟在bs4库中的是类似的。
- 父(Parent)
每个元素以及属性都有一个父。 - 子(Children)
元素节点可有零个、一个或多个子。 - 同胞(Sibling)
拥有相同的父的节点 - 先辈(Ancestor)
某节点的父、父的父,等等。 - 后代(Descendant)
某个节点的子,子的子,等等。
1.3 XPath语法
XPath 使用路径表达式来选取 XML 文档中的节点或节点集。节点是通过沿着路径 (path) 或者步 (steps) 来选取。
- 选取节点
XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
XPath要定位到我们需要的节点,多级选取和跳级选取中要多配合属性等来达到准确定位,其次要注意多余匹配情况的发生,检查结果是否准确!
表达式 | 描述 |
---|---|
nodename | 选取此节点下的所有子节点 |
/ | 多级选取,从根节点开始选取 |
// | 跳级选取,用的比较多,以列表形式,返回所有匹配的节点对象 |
. | 选取当前节点 |
… | 选取当前节点的父节点 |
@ | 选取属性 |
示例:
- 谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点。
谓语被嵌在方括号中。
在下面的表格中,列出了带有谓语的一些路径表达式,以及表达式的结果:
- 通配符-"*"
- 运算符 “|”
1.4 XPath 轴(Axes)
轴可定义相对于当前节点的节点集。
1.5 获取文本和属性信息
- 获取文本信息text()方法
result = html.xpath('//li/text()')
- 获取属性信息
result = html.xpath('//li/@属性名')
提取信息部分可以参考我的另外一篇文章Scrapy中XPath选择器的基本用法
2 项目实战——基于lxml+XPath+requests不登录爬取丁香园论坛的回复信息
2.1 目标
爬取丁香园论坛http://www.dxy.cn/bbs/thread/626626#626626上的回复内容。
说明:因为不登录只能爬取到4条。
2.2 思路
- 第一步准确定位到回复信息所在的标签
发现我们需要的信息都在<td class="postbody”>中,所以定位到这个标签。
# 以列表形式,返回所有包含所需信息的td标签
ls = tree.xpath('//td[@class="postbody"]')
- 第二步提取信息
我们需要的信息都在text中,对比string()和text()方法,我这里选择的是text(),因为它的打印输出比string()好一些。其中添加’\n’的作用是保证和原网页相近的格式输出(本质就是实现换行);
推荐大家看看我的这篇文章XPath中text方法和string方法的用法总结
ls_ms.append('\n'.join(ls[i].xpath('.//text()')).strip()) # 把每个td标签中的信息放入列表中
3 完整代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2019/4/9 13:41
@author: Jock
"""
import requests
from lxml import etree
import time
# get_html_text(url)获取网页信息
def get_html_text(url):
try:
r = requests.get(url) # 爬取完整的网页数据
r.raise_for_status() # 如果状态不是200,引发HTTPError异常
return r.text # 以字符串的形式返回爬取的网页内容
except:
print("访问出错")
return "" # 发生异常,返回空字符串
# extract_data(data)提取网页内容
def extract_data(data):
# 做好ElementTree
tree = etree.HTML(data)
# 列表ls_ms回复信息
ls_ms = []
# 以列表形式,返回所有包含所需信息的td标签
ls = tree.xpath('//td[@class="postbody"]')
n = len(ls)
for i in range(n):
try:
ls_ms.append('\n'.join(ls[i].xpath('.//text()')).strip()) # 把每个td标签中的信息放入列表中
except:
print('出错')
continue
return ls_ms
# 主函数
def main():
url = 'http://www.dxy.cn/bbs/thread/626626#626626'
data = get_html_text(url)
ls_ms = extract_data(data)
n = len(ls_ms)
print('【问题】:' + ls_ms[0])
for i in range(1,n):
print('【回复'+ str(i) + '】是:', end='')
print(ls_ms[i])
# 测试时间
def count_spend_time(func):
start_time = time.time()
func()
end_time = time.time()
time_dif = (end_time - start_time)
second = time_dif%60
minute = (time_dif//60)%60
hour = (time_dif//60)//60
print('spend ' + str(hour) + 'hours,' + str(minute) + 'minutes,' + str(second) + 'seconds')
if __name__ == '__main__':
count_spend_time(main)