python3爬虫学习笔记之解析库的使用----XPath篇(五)

在上面一章中,我们实现了一个最基本的爬虫,但是提取页面信息时使用的是正则表达式,这样的话,万一哪个地方写错了,就会导致整个匹配失败,所以很不方便。

对于页面的节点来说,它可以定义id、class或其他属性。节点之间还有层次关系,在网页中可以通过XPath或CSS选择器来定位一个或多个节点,然后通过调用响应方法获取它的正文内容或属性。

python中,解析库已经很多,比较强大的解析库有lxml、Beautiful Soup、pyquery等,接下来将讲解前两个解析库的用法。

XPath

XPath全称为XML Path Language,即XML路径语言,在XML文档中查找信息的语言。

XPath常用规则

表达式

描述

nodename

选取此节点的所有子节点

/

从当前节点选取直接子节点

//

从当前节点选取子孙节点

.

选取当前节点

..

选取当前节点的父节点

@

选取属性

如://title[@lang=’eng’]选择素有名称为title同时属性lang的值为’eng’的节点。

实例:

from lxml import etree

text = """
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul>
</div>
"""
html =etree.HTML(text)
result = etree.tostring(html)
print(result.decode('utf-8'))

运行结果:

这里先导入lxml库的etree模块,调用HTML类进行初始化,就构造了一个XPath解析对象。

还可以直接读取文本文件进行解析:

html = etree.parse('./test.html',etree.HTMLParser())
result = etree.tostring(html)
print(result.decode('utf-8'))

所有节点:

用//开头的XPath规则来选取所有符合要求的节点

result = html.xpath('//*')
print(result)

运行结果:

*代表匹配所有节点,这里返回的每个元素都是Element类型,后面跟了节点的名称,如html、body、div、ul、li、a等。

也可以为特殊名名称节点:

result = html.xpath('//li')

子节点:

可以通过/或//即可查找元素的子节点或子孙节点,如现在想选择li节点的所有直接a子节点

result = html.xpath('//li/a')

result = html.xpath('//ul//a')

父节点:

可以通过..(两点)查找父节点。

result = html.xpath('//a[@href="link4.html"]/../@class')
print(result)

结果为:['item-1'],打印li节点的class属性。

也可以通过parent::来获取父节点:

result = html.xpath('//a[@href="link4.html"]/parent::*/@class')

属性匹配:

可以通过@选取属性,从而达到过滤效果:

result = html.xpath('//li[@class="item-0"]')

文本获取:

可以用XPath中的text()方法获取节点中的文本,

result = html.xpath('//li[@class="item-0"]/text()')
print(result)
result = html.xpath('//li[@class="item-0"]/a/text()')
print(result)

运行结果:

分析:/选取直接子节点,li节点没有text。

属性获取:

result = html.xpath('//li/a/@href')
print(result)

多属性匹配:

如果一个节点有多个属性,

text = """
<li class="li li-first" name="item"><a href="link.html">first item</a><li>
"""
html = etree.HTML(text)
result = html.xpath('//li[contains(@class,"li") and @name="item"]/a/text()')
print(result)

按序选择:

result = html.xpath('//li[1]/a/text()')
print(result)
result = html.xpath('//li[last()]/a/text()')
print(result)
result = html.xpath('//li[position()<3]/a/text()')
print(result)
result = html.xpath('//li[last()-2]/a/text()')
print(result)

运行结果如下:

补充----获取指定节点的html源码

result = html.xpath('//ul')
print(result)
print(etree.tostring(result[0],encoding='utf-8'))

以上就是XPath的学习,接下来可以通过一个作业来实践以下:

利用requests和XPath爬取某个静态网页的内容,因为我们的目标是爬取新闻内容,所以这里以一个静态新闻网页为例子。(全部代码见news.py)

网页地址为:https://3w.huanqiu.com/a/b1c82f/9CaKrnKmLPE?agt=8

第一步:打开网址,可以看到下图

 

现在我们要爬取的是文章内容,包含标题,时间,作者,主内容,而不需要其他非相关东西。

第二步:打开开发者模式,查看源码

我们需要的内容在节点div class=”container”下的div class=”content-a”下,文章段落为p节点,标题为h1节点,信息为span节点,接下来就可以写代码了。见.py文件。

import requests
from lxml import etree

def get_html(url):
    headers={"User-Agent": 
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0"}

    response = requests.get(url,headers=headers)
    if response.status_code==200:
        return response.text
    return None

def main():
    url = 'https://3w.huanqiu.com/a/b1c82f/9CaKrnKmLPE?agt=8'
    html = get_html(url)
    html = etree.HTML(html)
    # 标题
    print('标题:')
    print(html.xpath('//div[@class="content-a" and @id="article"]//h1[@class="a-title"]/strong/text()'))
    #信息
    print('时间:')
    print(html.xpath('//div[@class="content-a" and @id="article"]//div[@class="a-info"]/span[1]/text()'))
    #责编
    print('责编:')
    print(html.xpath('//div[@class="content-a" and @id="article"]//div[@class="a-edit"]/span[1]/text()'))
    # 新闻内容
    print('新闻内容:')
    print(html.xpath('//div[@class="content-a" and @id="article"]//div[@class="a-con"]//p/text()'))
    
    # 新闻内容html代码,这样的话,图片链接还在
    html1 = etree.tostring(html.xpath('//div[@class="a-con"]')[0],encoding='utf-8')
    #print(html1.decode('utf-8'))
    html1 = etree.HTML(html1.decode('utf-8'))
    #print(html1.xpath('//p/text()'))

    
if __name__=='__main__':
    main()

 

 

如果对你有用,点个赞  手动笑脸(*_*)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值