上篇文章我们使用了原生正则表达式来解析网页,这次我们使用xpath来解析网页
安装xpath
pip install lxml
开始xpath
使用Xpath需要从lxml库中导入etree模块,还需使用HTML类对需要匹配的HTML对象进行初始化。HTML类的基本语法格式如下。
lxml.etree.HTML(text, parser=None, *, base_url=None)
参数名称 | 说明 |
---|---|
text | 接收str。表示需要转换为HTML的字符串。无默认值 |
parser | 接收str。表示选择的HTML解析器。无默认值 |
base_url | 接收str。表示设置文档的原始URL,用于在查找外部实体的相对路径。默认为None |
Xpath使用类似正则的表达式来匹配HTML文件中的内容,常用匹配表达式如下。
表达式 | 说明 |
---|---|
nodename | 选取nodename节点的所有子节点 |
/ | 从当前节点选取直接子节点 |
// | 从当前节点选取子孙节点 |
. | 选取当前节点 |
… | 选取当前节点的父节点 |
@ | 选取属性 |
Xpath中的谓语用来查找某个特定的节点或包含某个指定的值的节点,谓语被嵌在路径后的方括号中,如下。
表达式 | 说明 |
---|---|
/html/body/div[1] |
选取属于body子节点下的第一个div节点 |
/html/body/div[last()] |
选取属于body子节点下的最后一个div节点 |
/html/body/div[last()-1] |
选取属于body子节点下的倒数第二个div节点 |
/html/body/div[positon()<3] |
选取属于body子节点下的下前两个div节点 |
/html/body/div[@id] |
选取属于body子节点下的带有id属性的div节点 |
/html/body/div[@id=”content”] |
选取属于body子节点下的id属性值为content的div节点 |
/html /body/div[xx>10.00] |
选取属于body子节点下的xx元素值大于10的节点 |
功能函数 | 示例 | 说明 |
---|---|---|
starts-with | //div[starts-with(@id,”co”)] |
选取id值以co开头的div节点 |
contains | //div[contains(@id,”co”)] |
选取id值包含co的div节点 |
and | //div[contains(@id,”co”)andcontains(@id,”en”)] |
选取id值包含co和en的div节点 |
text() | //li[contains(text(),”first”)] |
选取节点文本包含first的div节点 |
了解了xpath,现在开始编写程序
需求: 还是和上一篇一样,只是今天我们需要把每篇新闻的文字正文保存到本地
我们先用浏览器的调试工具获取一下某个元素的xpath测试一下
[外链图片转存失败(img-XGDA9UJY-1564032836940)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]
得到结果
//*[@id="js_index2017_wrap"]/div[2]/div[2]/div[4]/div[1]/div[2]/div/div/div/div[1]/div[1]/div[2]/ul[1]/li[1]/a
我们可以结合上面过于xpath用法的表来看看这个xpath大家能理解不
我们加上text()获取一下标签内的文本
//*[@id="js_index2017_wrap"]/div[2]/div[2]/div[4]/div[1]/div[2]/div/div/div/div[1]/div[1]/div[2]/ul[1]/li[1]/a/text()
测试程序
# @File: code04.py
# @Author: lengwen
# @Time: 2019-07-25 11:37
# @Desc: xpath测试程序
import requests
from lxml import etree
url = 'http://www.163.com'
resp = requests.get(url)
# 初始化etree 转换为xpath
html_etree = etree.HTML(resp.text, parser=etree.HTMLParser(encoding='utf-8'))
# 使用xpath获取内容
result1 = html_etree.xpath('//*[@id="js_index2017_wrap"]/div[2]/div[2]/div[4]/div[1]/div[2]/div/div/div/div[1]/div[1]/div[2]/ul[1]/li[1]/a/text()')
print(result1)
接下来进入正题,我们先找到新闻链接的位置,这次我们就不使用浏览器的调试工具直接获取xpath了,因为大家开始看到那个xpath太长了
[外链图片转存失败(img-7vIRt5DM-1564032836943)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]
//div[@class="news_default_yw"]/ul/li/a[starts-with(@href,"https://news.163.com/")]/@href
# @File: code05.py
# @Author: lengwen
# @Time: 2019-07-25 12:01
# @Desc: xpath正式开始
import requests
from lxml import etree
url = 'http://www.163.com'
resp = requests.get(url)
# 初始化etree 转换为xpath
html_etree = etree.HTML(resp.text, parser=etree.HTMLParser(encoding='utf-8'))
# 构建xpath
result_url_list = html_etree.xpath(
'//div[@class="news_default_yw"]/ul/li/a[starts-with(@href,"https://news.163.com/")]/@href')
# 以写的方式打开url_list.txt这个文件
with open('./url_list.txt', 'w') as f:
for i in result_url_list:
print(i)
f.write(i + "\n")
接下来我们该爬取每个新闻的文字正文了
随便点进去一个链接可以看到文章的正文都在div.post_text>p
中,也就是我们构建xpath渠道div.post_text
下的所有p
的文字就可以了
构建xpath
//div[@class="post_text"]/p/text()
先看一段调试程序
# @File: code06.py
# @Author: lengwen
# @Time: 2019-07-25 12:26
# @Desc: 爬取新闻
import requests
from lxml import etree
with open('./url_list.txt') as f:
url = f.readline()
resp = requests.get(url)
html_etree = etree.HTML(resp.text, parser=etree.HTMLParser(encoding='utf-8'))
text = html_etree.xpath('//div[@class="post_text"]/p/text()')
for i in text:
print(i)
没有注释大家应该也能看懂了
结果
[外链图片转存失败(img-YE3RaXgb-1564032836944)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]
然后我们只需要加上循环,以及将爬取下来的内容保存就可以了
接下来看程序
# @File: code06.py
# @Author: lengwen
# @Time: 2019-07-25 12:26
# @Desc: 爬取新闻
import requests
from lxml import etree
import os
# 创建一个文件夹用于保存新闻
file_dir = 'news'
# 判断文件夹是否存在,不存在则创建
if not os.path.exists(file_dir):
os.mkdir(file_dir)
with open('./url_list.txt') as f:
# 按行读取文件
url = f.readline()
while url:
resp = requests.get(url)
html_etree = etree.HTML(resp.text, parser=etree.HTMLParser(encoding='utf-8'))
text = html_etree.xpath('//div[@class="post_text"]/p/text()')
# 获取标题作为文件名
title = html_etree.xpath('//title/text()')
print(title, '保存完成')
with open(os.path.join(file_dir, title[0] + '.txt'), 'w') as fw:
for i in text:
fw.write(i + '\n')
url = f.readline()
结果
[外链图片转存失败(img-JXVz9A39-1564032836945)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]
[外链图片转存失败(img-0bK1HWFL-1564032836946)(https://raw.githubusercontent.com/kevinlu98/cloudimg/master/data/[email protected])]
关于xpath的部分到此结束