我的爬虫学习之旅 (五) Xpath初识

前言

XPath是一种XML路径语言,适合于对HTML中的标签进行搜索。虽然学习过正则表达式,但是XPath的功能以及效率要比正则表达式方便的多,在python中要使用XPath,需要安装lxml库,lxml库是Python的一个解析库,支持HTML和XML的解析,支持XPath。

pip install lxml

一、XPath基础使用:

 

例如针对如下的一段html文本:

<div>
    <ul>
        <li class="item-0"><a href="www.baidu.com">baidu</a>
        <li class="item-1"><a href="https://blog.csdn.net/qq_25343557">myblog</a>
        <li class="item-2"><a href="https://www.csdn.net/">csdn</a>
        <li class="item-3"><a href="https://hao.360.cn/?a1004">hao123</a>

 首先用etree.HTML()方法构造出相应的解析对象:

from lxml import etree

html = etree.HTML(text)

显然可以看出这段文本代码是不完整的,可以使用etree模块中的etree.tostring()方法对文本进行补全:

res = etree.tostring(html)
print(res.decode('utf-8')) # 不进行编码则输出二进制格式

输出:

<html><body><div>
    <ul>
        <li class="item-0"><a href="www.baidu.com">baidu</a>
        </li><li class="item-1"><a href="https://blog.csdn.net/qq_25343557">myblog</a>
        </li><li class="item-2"><a href="https://www.csdn.net/">csdn</a>
        </li><li class="item-3"><a href="https://hao.360.cn/?a1004">hao123</a>
</li></ul></div></body></html>

除了对转换后的文本进行解析,也可以直接对文件进行解析,使用etree.parse()方法:

# 在工程路径下存放test.html文件
html = etree.parse('./test.html', etree.HTMLParser())
res = etree.tostring(html)
print(res.decode('utf-8'))

二、XPath基础语法:

在XPath语法中,每一对标签可视为一个结点,对使用etree解析的对象使用xpath()方法获取指定标签中的内容。

  • //:定位根路径,从文档中匹配当前节点之后的所有节点,而不考虑它们的位置。
  • /:定位当前路径的下一路径,当前结点为根节点。
  • .:当前结点
  • ..:当前节点的父节点
  • *:匹配任何元素
  • [ ]:谓语,可视作选择条件。
  • @:属性值
  • |:若干路径
  • contains():包含,contains(@class, 'class属性中的包含内容')
  • text():文本内容

获取所有结点

res = html.xpath('//*')

[<Element html at 0x133e6862f88>, <Element body at 0x133e6862f08>, <Element div at 0x133e6862ec8>, <Element ul at 0x133e6862fc8>, <Element li at 0x133e686d048>, <Element a at 0x133e686d0c8>, <Element li at 0x133e686d108>, <Element a at 0x133e686d148>, <Element li at 0x133e686d188>, <Element a at 0x133e686d088>, <Element li at 0x133e686d1c8>, <Element a at 0x133e686d208>]

获取指定结点下的子节点

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

 [<Element li at 0x1a38de6d0c8>, <Element li at 0x1a38de6d048>, <Element li at 0x1a38de6d108>, <Element li at 0x1a38de6d148>]

根据属性值获取结点

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

根据顺序选择结点: 

res = html.xpath('//li[4]/a/text()') # 与上例得到结果相同
res = html.xpath('//li[last()]/a/text()') # 获取最后一个<li>标签的<a>标签文本信息

获取标签中的属性

res = html.xpath('//li/@class')

 ['item-0', 'item-1', 'item-2', 'item-3']

获取标签下的文本信息

res = html.xpath('//li/a/text()')

['baidu', 'myblog', 'csdn', 'hao123']

根据包含的属性值获取结点: 

text = """
<div>
    <ul>
        <li class="item-0" name="one"><a href="www.baidu.com">baidu</a>
        <li class="item-1"><a href="https://blog.csdn.net/qq_25343557">myblog</a>
        <li class="item-2"><a href="https://www.csdn.net/">csdn</a>
        <li class="item-3"><a href="https://hao.360.cn/?a1004">hao123</a>
"""

html = etree.HTML(text)
res = html.xpath('//li[contains(@class, "item-0") and @name="one"]/a/text()|//li[@class="item-3"]/a/text()')
print(res)

三、XPath实战:

了解了XPath的用法后,对获取豆瓣电影TOP250的信息用XPath进行爬取。

import requests
from requests.exceptions import RequestException
from lxml import etree

def get_one_page(url):
    headers = {
        "User - Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
    }
    try:
        response = requests.get(url, headers = headers)
        if response.status_code == 200:
            return response.text
        else:
            print("获取数据失败,状态码:%d" %response.status_code)
            return None
    except RequestException:
        print("请求失败")
        return None

def write_to_file(content):
    with open("Douban250.txt", 'a', encoding="utf-8") as f:
        f.write(str(content) + '\n')
        f.close()

def parse_page(html):
    content = etree.HTML(html)
    all_data = content.xpath('//div[@id="content"]/div/div[1]/ol/li')

    for item in all_data:
        num = item.xpath('.//em/text()')[0]
        name = item.xpath('.//span[@class="title"][1]/text()')[0]
        pic = item.xpath('./div/div[1]/a/img/@src')[0]
        actors = item.xpath('./div/div[2]/div[2]/p/text()')[0]
        time = item.xpath('./div/div[2]/div[2]/p/text()')[1]
        score = item.xpath('.//div[@class="star"]/span[2]/text()')[0]
        peoples = item.xpath('.//div[@class="star"]/span[4]/text()')[0]

        info_dict = {
            "num": num,
            "name": name,
            "pic": pic,
            "actors": actors.strip(),
            "time": time.strip(),
            "score": score,
            "peoples": peoples
        }

        write_to_file(info_dict)

def main():
    for page in range(10):
        url = 'https://movie.douban.com/top250?start=' + str(25 * page)
        html = get_one_page(url)
        parse_page(html)

if __name__ == '__main__':
    main()

参考:

https://blog.csdn.net/qq_25343557/article/details/81912992

上一篇:LXML解析html代码和文件


下一篇:24 Scrapy爬虫的基本使用