优秀的编程知识分享平台

网站首页 > 技术文章 正文

爬虫之XPath语言解析(内有TP250爬虫实战)

nanyue 2024-11-14 16:47:33 技术文章 2 ℃

一、XPath简介及优势

XPath(XML Path Language)是一门在XML文档中查找信息的语言,它同样适用于HTML文档。XPath使用路径表达式来选取XML文档中的节点或节点集。通过使用XPath语言来定位网页中的数据,将会更加简单有效。


在Python中,使用XPath语言进行爬虫通常依赖于lxml库或BeautifulSoup库与lxml解析器的结合(尽管BeautifulSoup本身也支持自己的选择器语法,但可以配置为使用lxml作为解析器,从而允许在解析后的树结构上使用XPath)。然而,更常见的做法是直接使用lxml,因为它提供了对XPath的直接支持。

以下是如何在Python中使用lxml和XPath进行爬虫的步骤:

  1. 安装lxml库
    首先,你需要确保已经安装了lxml库。如果没有安装,可以使用pip进行安装:
  2. 发送HTTP请求并获取网页内容
    使用
    requests库发送HTTP请求并获取网页的HTML内容。如果没有安装requests库,也可以使用pip进行安装:
  3. 解析HTML内容
    使用lxml的html.fromstring方法将HTML内容解析为一个可操作的树结构。
  4. 使用XPath查询
    使用XPath表达式在解析后的树结构中查询特定的元素或元素集。
  5. 提取和处理数据
    从查询结果中提取所需的数据,并进行必要的处理。

以下是一个简单的示例代码,演示了如何使用lxml和XPath进行网页爬虫:

#导入库函数
import requests  
from lxml import html    

# 发送HTTP请求并获取网页内容  
url = 'http://example.com'  # 替换为你要爬取的网页URL  
response = requests.get(url)  
content = response.content    

# 解析HTML内容  
tree = html.fromstring(content)    

# 使用XPath查询特定的元素  
# 例如,查询所有的<a>标签,并获取它们的href属性和文本内容  
links = tree.xpath('//a/@href | //a/text()')    
# 注意:上面的XPath查询会返回一个混合了href属性和文本内容的列表  
# 如果你想要将它们分开,可以稍微修改XPath查询,或者使用Python代码来处理结果    
# 分开href属性和文本内容的示例(可能需要进一步处理,因为XPath不直接支持这种分组)  
hrefs = tree.xpath('//a/@href')  
texts = tree.xpath('//a/text()')    
# 由于hrefs和texts的长度可能不匹配(因为有些<a>标签可能没有文本内容,或者包含多个文本节点)  
# 你可能需要使用zip_longest来安全地迭代它们,并处理缺失的值  
from itertools import zip_longest    
for href, text in zip_longest(hrefs, texts, fillvalue='No Text'):  
    print(f'Link: {href}, Text: {text}')  
  
# 注意:上面的代码只是一个简单的示例,并没有处理网页中可能存在的相对URL、重复链接、JavaScript渲染的内容等问题  
# 在实际项目中,你可能需要更复杂的逻辑来处理这些情况

二、XPath基本语法

  1. 节点(Node)
  • XPath将XML文档视为节点树。
  • 节点可以是元素节点、属性节点、文本节点等。

2.路径表达式(Path Expression)

  • XPath使用路径表达式来选取节点。
  • 路径表达式可以包含节点名称、轴(axis)、谓词(predicate)等。

3.轴(Axis)

  • 轴定义了所选节点与当前节点之间的树关系。
  • 常见的轴包括child(子节点)、parent(父节点)、ancestor(祖先节点)、descendant(后代节点)等。

4.谓词(Predicate)

  • 谓词用于过滤节点。
  • 谓词被嵌在方括号[]中,并包含条件表达式。

三、XPath路径表达式示例

  1. 选取所有节点
  • 使用/从根节点选取。
  • 使用//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。

2.选取特定节点

  • 通过节点名称选取特定节点,如/bookstore/book选取所有book元素。

3.使用谓词过滤节点

  • 如//book[@category='WEB']选取所有category属性为WEB的book元素。

4.使用轴

  • 如child::book选取当前节点的所有book子节点。
  • ancestor::book选取当前节点的所有book祖先节点。

5.组合使用

  • 可以组合使用路径、轴和谓词来构建更复杂的查询。

四、XPath函数

XPath包含一组内建函数,用于字符串值、数值、日期和时间比较、节点和QName处理、序列处理等。以下是一些常用函数:

  • text():返回节点的文本内容。
  • contains(string1, string2):如果string1包含string2,则返回true,否则返回false。
  • starts-with(string, start-string):如果string以start-string开头,则返回true,否则返回false。
  • count(nodeset):返回节点集中的节点数。
  • concat(string1, string2, ...):连接两个或多个字符串。

五、XPath使用示例

在Python中,可以使用lxml库来解析XML或HTML文档,并使用XPath表达式来查询节点。

1.以下是一个简单的示例:

from lxml import etree  
  
# 解析HTML文档  
html_content = '''<html><body><h1>Hello World</h1><p>This is a paragraph.</p></body></html>'''  
tree = etree.HTML(html_content)  
  
# 使用XPath查询h1元素的文本内容  
h1_text = tree.xpath('//h1/text()')[0]  
print(h1_text)  # 输出: Hello World

在这个示例中,我们首先使用etree.HTML方法解析了HTML文档,然后使用XPath表达式//h1/text()查询了h1元素的文本内容,并将其打印出来。

2.使用XPath语法爬取豆瓣电影Top 250。你需要使用一种编程语言(如Python)和一个爬虫库(如requestslxmlBeautifulSoup)。以下是一个使用Python和requestslxml库来爬取豆瓣电影Top 250的示例代码。

import requests  
from lxml import etree  
  
# 豆瓣电影Top 250的基础URL  
base_url = 'https://movie.douban.com/top250'  
headers = {  
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'  
}  
  
# 存放所有电影信息的列表  
movies = []  
  
# 爬取每一页的数据,豆瓣电影Top 250一共10页  
for start in range(0, 250, 25):  
    url = f'{base_url}?start={start}&filter='  
    response = requests.get(url, headers=headers)  
      
    if response.status_code == 200:  
        # 使用lxml解析HTML  
        tree = etree.HTML(response.text)  
          
        # 使用XPath查找电影信息  
        movie_items = tree.xpath('//div[@class="info"]')  
          
        for item in movie_items:  
            rank = item.xpath('.//em[@class=""]/text()')
            title = item.xpath('.//span[@class="title"]/text()')[0]  
            rating_num = item.xpath('.//span[@class="rating_num"]/text()')[0]  
            quote = item.xpath('.//span[@class="inq"]/text()')  
            quote = quote[0] if quote else "No quote"  
              
            movies.append({  
                'rank': rank,  
                'title': title,  
                'rating_num': rating_num,  
                'quote': quote  
            })  
  
# 打印爬取到的电影信息  
for movie in movies:  
    print(f"Rank: {movie['rank']}, Title: {movie['title']}, Rating: {movie['rating_num']}, Quote: {movie['quote']}")  
  
# 也可以将数据存储到文件或其他地方  
# 例如,使用json库存储到JSON文件  
import json  
with open('douban_top250.json', 'w', encoding='utf-8') as f:  
    json.dump(movies, f, ensure_ascii=False, indent=4)

解释

    1. 导入库:导入requests用于发送HTTP请求,lxml用于解析HTML和XPath查询。
    2. 设置基础URL和请求头:设置豆瓣电影Top 250的基础URL,并添加一个User-Agent头以避免被反爬虫机制阻止。
    3. 初始化电影信息列表:创建一个空列表来存储所有电影的信息。
    4. 循环爬取每一页:豆瓣电影Top 250一共10页,每页25部电影,通过循环range(0, 250, 25)来生成每页的URL。
    5. 发送请求并解析HTML:使用requests.get发送请求,并使用lxml.etree.HTML解析HTML内容。
    6. 使用XPath查找电影信息:通过XPath查找电影排名、标题、评分和引言。
    7. 存储电影信息:将找到的电影信息存储到列表中。
    8. 打印或存储电影信息:最后,打印或存储爬取到的电影信息。

注意事项

  1. 反爬虫机制:频繁访问可能会触发豆瓣的反爬虫机制,建议添加延时(如time.sleep)或在请求之间增加随机延时。
  2. 合法性:确保你的爬虫行为符合网站的robots.txt规定和当地法律法规。
  3. 动态内容:如果豆瓣网站结构发生变化或使用了JavaScript动态加载内容,可能需要使用Selenium等更强大的工具。

希望本文对大家有所帮助,也欢迎在留言区讨论。

Tags:

最近发表
标签列表