Python爬虫技术 第16节 XPath

XPath是一种在XML文档中查找信息的语言,尽管XML和HTML在语法上有区别,但XPath同样适用于HTML文档的解析,尤其是在使用如lxml这样的库时。XPath提供了一种强大的方法来定位和提取XML/HTML文档中的元素和属性。

XPath基础

XPath表达式由路径表达式组成,它们指定了文档中的位置。下面是一些基本的XPath语法:

  1. 根节点

    • / 表示绝对路径的开始,指向文档的根节点。
    • // 表示从当前位置到文档的任意位置。
  2. 元素选择

    • elementName 选择该名称下的所有子节点。
    • @attributeName 选择指定的属性。
  3. 路径操作

    • child/ 选择当前节点的直接子节点。
    • .. 移动到父节点。
    • . 当前节点。
  4. 位置路径

    • last() 返回集合中的最后一个节点的位置。
    • position() 返回节点在其父节点中的位置。
  5. 过滤器

    • [condition] 过滤节点,如 [contains(text(), 'keyword')]
    • [1] 选择第一个节点。
    • [last()] 选择最后一个节点。
    • [position()=odd] 选择位置为奇数的节点。
    • ancestor::* 选择所有祖先节点。
    • following-sibling::* 选择当前节点之后的所有同级节点。
    • preceding-sibling::* 选择当前节点之前的所有同级节点。

使用Python和lxml库

假设你有以下HTML文档:

<div id="container"><h1>Title</h1><div class="content"><p>Paragraph 1</p><p>Paragraph 2</p></div><div class="sidebar"><ul><li>Item 1</li><li>Item 2</li></ul></div>
</div>

使用lxml库解析和提取数据:

from lxml import etreehtml = '''
<div id="container"><h1>Title</h1><div class="content"><p>Paragraph 1</p><p>Paragraph 2</p></div><div class="sidebar"><ul><li>Item 1</li><li>Item 2</li></ul></div>
</div>
'''root = etree.fromstring(html)# 获取标题
title = root.xpath('//h1/text()')
print("Title:", title[0])# 获取所有段落
paragraphs = root.xpath('//div[@class="content"]/p/text()')
print("Paragraphs:", paragraphs)# 获取列表项
items = root.xpath('//div[@class="sidebar"]/ul/li/text()')
print("Items:", items)

使用Scrapy框架

Scrapy是一个用于Web爬取的框架,内置支持XPath和CSS选择器。下面是如何在Scrapy项目中使用XPath:

import scrapyclass MySpider(scrapy.Spider):name = 'myspider'start_urls = ['http://example.com']def parse(self, response):# 获取标题title = response.xpath('//h1/text()').get()yield {'title': title}# 获取所有段落paragraphs = response.xpath('//div[@class="content"]/p/text()').getall()yield {'paragraphs': paragraphs}# 获取列表项items = response.xpath('//div[@class="sidebar"]/ul/li/text()').getall()yield {'items': items}

XPath与CSS选择器的比较

虽然XPath提供了更强大的查询能力,但CSS选择器通常在HTML文档中更直观易读。XPath更适合处理复杂的查询,尤其是在需要跨层级或根据条件过滤节点的情况下。然而,对于简单的结构化文档,CSS选择器往往足够使用,而且代码更为简洁。

在实际应用中,可以根据具体需求和文档结构选择使用XPath或CSS选择器。大多数现代的Python Web爬取库都同时支持这两种选择器。

当然,可以考虑以下几个方面:增加错误处理、处理更复杂的HTML结构、提取嵌套数据以及执行多次请求来处理动态加载的内容。下面我将展示如何使用Python和lxml库来实现这些功能。

错误处理和异常管理

在使用XPath进行网页爬取时,应考虑到可能发生的错误,如网络问题、无效的XPath表达式、找不到期望的元素等。这里是一个带有错误处理的示例:

from lxml import etree
import requestsdef fetch_html(url):try:response = requests.get(url)response.raise_for_status()return response.textexcept requests.RequestException as e:print(f"Request error: {e}")return Nonedef parse_html(html):if html is None:print("Failed to fetch HTML")returntry:tree = etree.HTML(html)title = tree.xpath('//h1/text()')if title:print("Title:", title[0])else:print("Title not found")paragraphs = tree.xpath('//div[@class="content"]/p/text()')if paragraphs:print("Paragraphs:", paragraphs)else:print("No paragraphs found")items = tree.xpath('//div[@class="sidebar"]/ul/li/text()')if items:print("Items:", items)else:print("No items found")except etree.XPathEvalError as e:print(f"XPath evaluation error: {e}")def main():url = "http://example.com"html = fetch_html(url)parse_html(html)if __name__ == "__main__":main()

处理更复杂的HTML结构

有时网页结构可能包含嵌套的元素,或者有多个相似的元素。XPath允许你使用更复杂的表达式来处理这些情况。例如,如果每个列表项都有额外的信息,可以使用如下XPath表达式:

items_with_details = tree.xpath('//div[@class="sidebar"]/ul/li')
for item in items_with_details:item_text = item.xpath('./text()')item_link = item.xpath('.//a/@href')print("Item:", item_text, "Link:", item_link)

处理动态加载的内容

如果网站使用JavaScript动态加载内容,单次请求可能无法获取全部数据。在这种情况下,可以使用Selenium或Requests-HTML库来模拟浏览器行为。以下是使用Requests-HTML的示例:

from requests_html import HTMLSessionsession = HTMLSession()def fetch_and_render(url):r = session.get(url)r.html.render(sleep=1)  # Wait for JavaScript to executereturn r.html.raw_html.decode('utf-8')def main():url = "http://example.com"html = fetch_and_render(url)tree = etree.HTML(html)# Now you can use XPath on the rendered HTML...if __name__ == "__main__":main()

请注意,使用像Selenium这样的工具可能会显著增加你的爬虫脚本的资源消耗和运行时间,因为它模拟了一个完整的浏览器环境。

通过这些扩展,你的XPath代码将更加健壮,能够处理更复杂和动态的网页结构。在开发爬虫时,始终记得遵守网站的robots.txt规则和尊重网站的使用条款,避免过度请求导致的服务压力。

接下来,我们可以引入一些最佳实践,比如:

  1. 模块化:将代码分解成多个函数,提高可读性和可维护性。
  2. 参数化:使函数接受参数,以便于复用和配置。
  3. 日志记录:记录关键步骤和潜在的错误信息,便于调试和监控。
  4. 并发处理:利用多线程或多进程处理多个URL,提高效率。
  5. 重试机制:在网络不稳定时自动重试失败的请求。
  6. 数据存储:将提取的数据保存到文件或数据库中。

下面是一个使用上述最佳实践的代码示例:

import logging
import requests
from lxml import etree
from time import sleep
from concurrent.futures import ThreadPoolExecutor, as_completedlogging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')def fetch_html(url, max_retries=3, delay=1):"""Fetch HTML from a given URL with retry mechanism."""for attempt in range(max_retries):try:response = requests.get(url)response.raise_for_status()return response.textexcept requests.RequestException as e:logging.error(f"Error fetching URL: {url}, attempt {attempt + 1}/{max_retries}. Error: {e}")if attempt < max_retries - 1:sleep(delay * (attempt + 1))  # Exponential backoffreturn Nonedef parse_html(html, xpath_expression):"""Parse HTML using provided XPath expression."""if html is None:logging.error("Failed to fetch HTML")return Nonetry:tree = etree.HTML(html)result = tree.xpath(xpath_expression)return resultexcept etree.XPathEvalError as e:logging.error(f"XPath evaluation error: {e}")return Nonedef save_data(data, filename):"""Save data to a file."""with open(filename, 'w') as f:f.write(str(data))def process_url(url, xpath_expression, output_filename):"""Process a single URL by fetching, parsing, and saving data."""logging.info(f"Processing URL: {url}")html = fetch_html(url)data = parse_html(html, xpath_expression)if data:save_data(data, output_filename)logging.info(f"Data saved to {output_filename}")def main(urls, xpath_expression, output_dir):"""Main function to process multiple URLs concurrently."""with ThreadPoolExecutor(max_workers=5) as executor:futures = []for url in urls:output_filename = f"{output_dir}/data_{url.split('/')[-1]}.txt"future = executor.submit(process_url, url, xpath_expression, output_filename)futures.append(future)for future in as_completed(futures):future.result()if __name__ == "__main__":urls = ["http://example1.com", "http://example2.com"]xpath_expression = '//div[@class="content"]/p/text()'  # Example XPath expressionoutput_dir = "./output"main(urls, xpath_expression, output_dir)

在这个例子中,我们定义了以下几个关键函数:

  • fetch_html:负责从URL获取HTML,具有重试机制。
  • parse_html:使用提供的XPath表达式解析HTML。
  • save_data:将数据保存到文件。
  • process_url:处理单个URL,包括获取HTML、解析数据并保存。
  • main:主函数,使用线程池并行处理多个URL。

这种结构允许你轻松地扩展爬虫的功能,比如添加更多的URL或XPath表达式,同时保持代码的清晰和可维护性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/50458.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何检查代理IP地址是否被占用

使用代理IP时&#xff0c;有时候会发现IP仍然不可用&#xff0c;可能是因为已经被其他用户或者网络占用了。为了检测代理IP是否被占用&#xff0c;我们可以采用一些方法进行验证测试&#xff0c;以保证代理IP的有效性和稳定性。 1.ARP缓存方法 ARP缓存法是一种简单有效的检测代…

Cesium 实现点击获取实体的 ID 值

文章目录 需求分析需求 点击球体上加载的实体,获取该实体的 ID 值 分析 var handler = new Cesium.ScreenSpaceEventHandler(this.map.scene.canvas); // 创建鼠标事件handler const that = this handler.setInputAction(</

Tinygrad,llama3,Reward Model

目录 Tinygrad 与其他框架的比较 llama3 Reward Model Tinygrad 是一个轻量级的深度学习框架,由George Hotz(也被称为geohot)开发。以下是对Tinygrad的详细介绍: 与其他框架的比较 与PyTorch、TensorFlow等更全面的深度学习框架相比,Tinygrad在功能上可能有所限制,…

Unity UGUI 之 事件接口

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 本文在发布时间选用unity 2022.3.8稳定版本&#xff0c;请注意分别 1.什么是事件接口&…

【github】使用KeepassXC 解决github Enable two-factor authentication (2FA) 第二因子认证

下载 https://github.com/keepassxreboot/keepassxc/releases/download/2.7.9/KeePassXC-2.7.9-Win64.msi 代理地址 https://dgithub.xyz/keepassxreboot/keepassxc/releases/download/2.7.9/KeePassXC-2.7.9-Win64.msi 由于该软件不允许截图&#xff0c;以下操作参考官网 …

JavaScript模拟滑动手势

双击回到顶部 左滑动 右滑动 代码展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Gesture…

力扣高频SQL 50题(基础版)第八题

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第八题1581. 进店却未进行过交易的顾客题目说明思路分析实现过程准备数据&#xff1a;实现方式&#xff1a;结果截图&#xff1a;总结&#xff1a; 力扣高频SQL 50题&#xff08;基础版&#xff09;第八题 1581. 进店…

.NET Core 发展历程和版本迭代

.NET Core的发展历程和版本迭代可以归纳如下&#xff1a; 目录 一、起源与发展&#xff08;2010-2016&#xff09; 二、成熟与优化&#xff08;2017-2019&#xff09; 三、整合与统一&#xff08;2020至今&#xff09; 四、版本特性简述 五、版本更新迭代的功能区别 .NET…

jenkins删除历史构建记录

1、 登录jenkins&#xff0c;进入【Manage Jenkins】-【Script Console】&#xff0c;输入&#xff1a; def jobName "Test" //删除的项目名称 def maxNumber 60 // 保留的最小编号&#xff0c;意味着小于该编号的构建都将被删除 Jenkins.instance.getItemByFullN…

mybatis 多数据源 TDataSource required a single bean, but 2 were found

情况说明&#xff1a; 项目中本来就有一个数据源了&#xff0c;运行的好好的后来又合并了另一个项目&#xff0c;另一个项目也配置了数据源。 于是出现了如下错误&#xff1a; mybatis 多数据源 TDataSource required a single bean, but 2 were found 解决方法&#xff1a…

CSS前端面试题——怎么用CSS实现一个宽高自适应的正方形?

方法一&#xff1a;使用 padding 方案 这种方法通过设置元素的 padding 属性来实现宽高比例相等的正方形。假设我们希望正方形的边长为相对于父容器的百分比值&#xff0c;比如50% .square {width: 50%; /* 可以是任意宽度&#xff0c;这里假设为父元素宽度的50% */padding-t…

【深度学习】语音合成,TTS,ChatTTS项目体验

项目&#xff1a; https://github.com/2noise/ChatTTS/blob/main/README.md 这个fork项目不错&#xff1a; https://github.com/Jackiexiao/ChatTTS-api-ui-docker docker run \--gpus all --ipchost \--ulimit memlock-1 --ulimit stack67108864 \-p 8080:8080 -p 8501:850…

【反证法】932. 漂亮数组

本文涉及知识点 分治 数学 反证法 LeetCode932. 漂亮数组 如果长度为 n 的数组 nums 满足下述条件&#xff0c;则认为该数组是一个 漂亮数组 &#xff1a; nums 是由范围 [1, n] 的整数组成的一个排列。 对于每个 0 < i < j < n &#xff0c;均不存在下标 k&#x…

Python练手小项目

计算器 创建一个简单的计算器&#xff0c;能够进行加、减、乘、除四种基本运算。 # 定义加法函数 def add(x, y):return x y# 定义减法函数 def subtract(x, y):return x - y# 定义乘法函数 def multiply(x, y):return x * y# 定义除法函数 def divide(x, y):if y 0:return…

华为Ascend C算子开发(中级)考试

华为Ascend C算子开发&#xff08;中级&#xff09;考试题 提示&#xff1a;这个是河北廊坊Ascend C算子开发考试题和答案&#xff0c;仅供参考&#xff0c;因为不确定其他城市的考试题是否也是一样 文章目录 华为Ascend C算子开发&#xff08;中级&#xff09;考试题一、op_ho…

kafka源码阅读-Broker如何处理生产者的消息写入请求

概述 Kafka源码包含多个模块&#xff0c;每个模块负责不同的功能。以下是一些核心模块及其功能的概述&#xff1a; 服务端源码 &#xff1a;实现Kafka Broker的核心功能&#xff0c;包括日志存储、控制器、协调器、元数据管理及状态机管理、延迟机制、消费者组管理、高并发网络…

端到端自动驾驶科普向

从设计思想看&#xff0c;自动驾驶系统分为模块化和黑箱化两个大类。前者将系统分解为一系列功能独立的模块&#xff0c;每一个模块单独设计&#xff0c;组合到一起实现自动驾驶功能&#xff08;我们熟知的定位 感知 规划 控制 决策等模块&#xff09;&#xff1b;后者又称为端…

Python爬虫技术 第13节 HTML和CSS选择器

在爬虫技术中&#xff0c;解析和提取网页数据是核心部分。HTML 和 CSS 选择器被广泛用于定位网页中的特定元素。下面将详细介绍这些选择器如何在 Python 中使用&#xff0c;特别是在使用像 Beautiful Soup 或 Scrapy 这样的库时。 HTML 选择器 HTML 选择器基于 HTML 元素的属性…

基于微信小程序+SpringBoot+Vue的美食推荐平台(带1w+文档)

基于微信小程序SpringBootVue的美食推荐平台(带1w文档) 基于微信小程序SpringBootVue的流浪动物救助(带1w文档) 当微信小程序占领了多半江山&#xff0c;目前不分年龄和种族&#xff0c;使用频率最高&#xff0c;覆盖面积最广。使用人群使用的大多数都是微信小程序。目前国内最…

Kithara和Halcon (二)

Kithara使用Halcon QT 进行二维码实时识别 目录 Kithara使用Halcon QT 进行二维码实时识别Halcon 简介以及二维码检测的简要说明Halcon 简介Halcon的二维码检测功能 Qt应用框架简介项目说明关键代码抖动测试测试平台&#xff1a;测试结果&#xff1a; 开源源码 Halcon 简介以…