面向初学者的 Python 分步式网络搜索指南

评论: 0

Python 因其强大的库和简单的语法而成为网络搜索的首选。在本文中,我们将探讨网络刮擦的基础知识,并指导您设置 Python 环境,创建第一个网络刮擦程序。我们将向您介绍适用于刮擦任务的关键 Python 库,包括 Beautiful Soup、Playwright 和 lxml。

用于网络搜索的 Python 库

Python 提供了多个库,使网络搜索变得更容易。下面是一些最常用的库:

  • requests: 是 Python 的一个简单而优雅的 HTTP 库,用于发送 HTTP 请求以获取网页。
  • Beautiful Soup: 是解析 HTML 和 XML 文档的利器。它能从页面源代码中创建解析树,便于提取数据。
  • lxml: lxml 以速度和效率著称,是解析 XML 和 HTML 文档的绝佳工具。
  • Playwright: 是一款用于动态内容搜刮和网页交互的强大工具。

HTTP 请求简介

HTTP(超文本传输协议)是一种在网络上传输数据的应用层协议。你在浏览器中输入一个 URL,浏览器就会生成一个 HTTP 请求并将其发送给网络服务器。然后,网络服务器将 HTTP 响应发送回浏览器,浏览器再将其渲染为 HTML 页面。对于网页抓取,你需要模仿这一过程,从脚本中生成 HTTP 请求,以编程方式获取网页的 HTTP 内容。

设置环境

首先,确保您的系统已安装 Python。您可以从 Python 的官方网站下载。

虚拟环境有助于管理依赖关系。使用这些命令创建并激活虚拟环境:


python -m venv scraping_env
source scraping_env/bin/activate

接下来,使用以下命令安装所需的软件包:


pip install requests
pip install beautifulsoup4 
pip install lxml

用 Beautiful Soup 创建网络搜刮器

让我们从一个简单的网络抓取器开始,使用请求抓取静态 HTML 内容。

进行 HTTP GET 请求

最常见的 HTTP 请求类型是 GET 请求,用于从指定的 URL 获取数据。下面是一个如何向 http://example.com 执行 GET 请求的基本示例。


import requests
url = 'http://example.com'
response = requests.get(url)

处理 HTTP 响应

请求库提供了几种处理响应的方法:

检查状态代码:确保请求成功。


if response.status_code == 200:
    print('Request was successful!')
else:
    print('Request failed with status code:', response.status_code)

提取内容:从响应中提取文本或 JSON 内容。


# 以文本形式获取响应内容
page_content = response.text
print(page_content)

# 以 JSON 格式获取响应内容(如果响应是 JSON 格式)
json_content = response.json()
print(json_content)

处理 HTTP 和网络错误

当资源无法到达、请求超时或服务器返回错误 HTTP 状态(如 404 Not Found、500 Internal Server Error)时,可能会发生 HTTP 和网络错误。我们可以使用请求引发的异常对象来处理这些情况。


import requests

url = 'http://example.com'

try:
    response = requests.get(url, timeout=10)  # Set a timeout for the request
    response.raise_for_status()  # Raises an HTTPError for bad responses
except requests.exceptions.HTTPError as http_err:
    print(f'HTTP error occurred: {http_err}')
except requests.exceptions.ConnectionError:
    print('Failed to connect to the server.')
except requests.exceptions.Timeout:
    print('The request timed out.')
except requests.exceptions.RequestException as req_err:
    print(f'Request error: {req_err}')
else:
    print('Request was successful!')

从 HTML 元素中提取数据

在网络刮擦中,我们经常需要从 HTML 内容中提取数据。本部分将介绍如何使用一些库(如 Beautiful Soup 或 lxml)从 HTML 元素中定位和提取数据。

HTML(超文本标记语言)是创建网页的标准标记语言。它由嵌套元素组成,用标签表示,如<div>、<p>、<a>等。每个标签都可以有属性,包含文本、其他标签或两者。

XPath 和 CSS 选择器提供了一种多用途方法,可根据 HTML 元素的属性或其在文档中的位置来选择 HTML 元素。

查找 XPath 和 CSS 选择器

在网络搜刮时,要从网页中提取特定数据,往往需要识别正确的 XPath 或 CSS 选择器来定位 HTML 元素。以下是如何高效查找这些选择器的方法:

大多数现代网络浏览器都内置了开发工具,可以检查网页的 HTML 结构。以下是如何使用这些工具的分步指南:

  1. 开放开发人员工具:
    • 在 Chrome 浏览器中:右键单击页面并选择 "检查",或按 Ctrl+Shift+I (Windows/Linux) 或 Cmd+Opt+I (Mac)。
    • 在火狐浏览器中右键单击页面并选择 "检查元素",或按 Ctrl+Shift+I (Windows/Linux) 或 Cmd+Opt+I (Mac)。
  2. 检查元件:
    • 使用检查工具(光标图标)悬停并单击要扫描的元素。这将在 HTML 结构视图中突出显示该元素。
  3. 复制 XPath 或 CSS 选择器:
    • 右键单击开发工具窗格中高亮显示的 HTML 元素。
    • 选择 "复制",然后选择 "复制 XPath "或 "复制选择器"(CSS 选择器)。

1n.png

XPath: /html/body/div/h1

CSS Selector: body > div > h1

使用美丽汤提取

Beautiful Soup 是一个用于解析 HTML 和 XML 文档的 Python 库。它提供了简单的方法和属性来浏览和搜索 HTML 结构。


from bs4 import BeautifulSoup
import requests

# 要搜索的网页的 URL
url = 'https://example.com'

# 向 URL 发送 HTTP GET 请求
response = requests.get(url)

# 使用 Beautiful Soup 解析响应的 HTML 内容
soup = BeautifulSoup(response.content, 'html.parser')

# 使用 CSS 选择器查找 <div> 标记内的所有 <h1> 标记
# 作为<body>标记直接子代的所有<h1>标记
h1_tags = soup.select('body > div > h1')

# 遍历找到的 <h1> 标记列表并打印其文本内容
for tag in h1_tags:
    print(tag.text)

处理解析错误

当 HTML 或 XML 结构与预期不符时,就会出现解析错误,从而导致数据提取问题。可以通过处理 AttributeError 等异常来管理这些错误。


from bs4 import BeautifulSoup
import requests

# 要搜索的网页的 URL
url = 'https://example.com'

# 向 URL 发送 HTTP GET 请求
response = requests.get(url)

try:
    # 使用 Beautiful Soup 解析响应的 HTML 内容
    soup = BeautifulSoup(response.content, 'html.parser')

    # 使用 CSS 选择器查找 <div> 标记内的所有 <h1> 标记
    # 作为<body>标记直接子代的所有<h1>标记
    h1_tags = soup.select('body > div > h1')

    # 遍历找到的 <h1> 标记列表并打印其文本内容
    for tag in h1_tags:
        print(tag.text)
except AttributeError as attr_err:
    # 处理可能出现 AttributeError 的情况(例如,当 response.content 为 None 时)
    print(f'Attribute error occurred: {attr_err}')
except Exception as parse_err:
    # 处理解析过程中可能出现的任何其他异常
    print(f'Error while parsing HTML: {parse_err}')

使用 lxml 提取

除了 Beautiful Soup,另一个在 Python 中解析 HTML 和 XML 文档的流行库是 lxml。BeautifulSoup 侧重于为导航和操作解析后的数据提供方便的界面,而 lxml 则以速度和灵活性著称,使其成为对性能要求较高的任务的首选。


from lxml.html import fromstring
import requests

# 要搜索的网页的 URL
url = 'https://example.com'

# 向 URL 发送 HTTP GET 请求
response = requests.get(url)

# 使用 lxml 的 fromstring 方法解析响应的 HTML 内容
parser = fromstring(response.text)

# 使用 XPath 查找第一个<h1>标记的文本内容
# 位于 <div> 标记内,该标记是 <body> 标记的直接子标记
title = parser.xpath('/html/body/div/h1/text()')[0]

# 打印标题
print(title)

处理解析错误

与 Beautiful Soup 类似,lxml 也可以通过捕获类似 lxml.etree.XMLSyntaxError 这样的异常,优雅地处理解析错误。


from lxml.html import fromstring
from lxml import etree
import requests

# 要搜索的网页的 URL
url = 'https://example.com'

# 向 URL 发送 HTTP GET 请求
response = requests.get(url)

try:
    # 使用 lxml 的 fromstring 方法解析响应的 HTML 内容
    parser = fromstring(response.text)

    # 使用 XPath 查找第一个<h1>标记的文本内容
    # 位于 <div> 标记内,该标记是 <body> 标记的直接子标记
    title = parser.xpath('/html/body/div/h1/text()')[0]

    # 打印标题
    print(title)
except IndexError:
    # 处理 XPath 查询不返回任何结果的情况
    print('No <h1> tag found in the specified location.')
except etree.XMLSyntaxError as parse_err:
    # 在解析过程中处理 XML 语法错误
    print(f'Error while parsing HTML: {parse_err}')
except Exception as e:
    # 处理任何其他异常
    print(f'An unexpected error occurred: {e}')

保存提取的数据

从 HTML 元素中成功提取数据后,下一步就是保存这些数据。Python 提供了多种保存刮擦数据的选项,包括保存到 CSV 文件、JSON 文件和数据库。下面概述了如何使用不同格式保存提取的数据:

将数据保存到 CSV 文件

CSV(逗号分隔值)是一种简单而广泛使用的表格数据存储格式。Python 中的 CSV 模块可以轻松地将数据写入 CSV 文件。


import csv

# 样本数据
data = {
    'title': 'Example Title',
    'paragraphs': ['Paragraph 1', 'Paragraph 2', 'Paragraph 3']
}

# 将数据保存为 CSV 文件
with open('scraped_data.csv', mode='w', newline='', encoding='utf-8') as file:
    writer = csv.writer(file)
    writer.writerow(['Title', 'Paragraph'])
    for paragraph in data['paragraphs']:
        writer.writerow([data['title'], paragraph])

print('Data saved to scraped_data.csv')

将数据保存到 JSON 文件

JSON(JavaScript Object Notation,JavaScript 对象符号)是一种轻量级数据交换格式,易于读写。Python 中的 JSON 模块提供了以 JSON 格式保存数据的方法。


import json

# 样本数据
data = {
    'title': 'Example Title',
    'paragraphs': ['Paragraph 1', 'Paragraph 2', 'Paragraph 3']
}

# 将数据保存到 JSON 文件
with open('scraped_data.json', mode='w', encoding='utf-8') as file:
    json.dump(data, file, ensure_ascii=False, indent=4)

print('Data saved to scraped_data.json')

使用 Playwright 高级网络刮擦技术

Playwright 是一款功能强大的工具,可用于采集动态内容并与网页元素进行交互。它可以处理静态 HTML 解析器无法处理的 JavaScript 繁重网站。

安装 Playwright 并进行设置:


pip install playwright
playwright install

抓取动态内容

Playwright 允许你与网络元素进行交互,如填写表格和点击按钮。它可以等待 AJAX 请求完成后再继续操作,因此非常适合于采集动态内容。

2n.png

所提供的代码使用 Playwright 和 lxml 对亚马逊产品页面执行网络刮擦。首先,导入必要的模块。定义了一个运行函数来封装搜索逻辑。该函数首先会设置一个代理服务器,并通过代理以非无头模式启动一个新的浏览器实例,以便我们观察浏览器的操作。在浏览器上下文中,打开一个新页面并导航到指定的亚马逊产品 URL,超时 60 秒以确保页面完全加载。

然后,脚本与页面交互,通过使用定位器和文本匹配,从下拉菜单和产品选项中选择特定的产品样式。在确保这些交互完成且页面再次完全加载后,就会捕获页面的 HTML 内容。

然后使用 lxml 的 fromstring 方法解析 HTML 内容,创建元素树。使用 XPath 查询从 ID 为 productTitle 的特定元素中提取产品标题的文本内容。该脚本包含错误处理功能,可处理 XPath 查询不返回结果、解析过程中出现 XML 语法错误或其他意外异常的情况。最后,会打印 tlxml 提取的产品标题,并关闭浏览器上下文和浏览器以结束会话。

运行函数在由 sync_playwright 启动的 Playwright 会话中执行,确保整个过程在受控环境中管理和执行。这种结构可确保在执行网络刮擦任务时的稳健性和抗错能力。


from playwright.sync_api import Playwright, sync_playwright
from lxml.html import fromstring, etree


def run(playwright: Playwright) -> None:
   # 定义代理服务器
   proxy = {"server": "https://IP:PORT", "username": "LOGIN", "password": "PASSWORD"}

   # 使用指定代理并以非无头模式启动一个新的浏览器实例
   browser = playwright.chromium.launch(
       headless=False,
       proxy=proxy,
       slow_mo=50,
       args=['--ignore-certificate-errors'],
   )

   # 创建新的浏览器上下文
   context = browser.new_context(ignore_https_errors=True)

   # 在浏览器上下文中打开新页面
   page = context.new_page()

   # 导航至指定的亚马逊产品页面
   page.goto(
       "https://www.amazon.com/A315-24P-R7VH-Display-Quad-Core-Processor-Graphics/dp/B0BS4BP8FB/",
       timeout=10000,
   )

   # 等待页面完全加载
   page.wait_for_load_state("load")

   # 从下拉菜单中选择特定产品样式
   page.locator("#dropdown_selected_style_name").click()

   # 选择特定产品选项
   page.click('//*[@id="native_dropdown_selected_style_name_1"]')
   page.wait_for_load_state("load")

   # 获取已加载页面的 HTML 内容
   html_content = page.content()

   try:
       # 使用 lxml 的 fromstring 方法解析 HTML 内容
       parser = fromstring(html_content)

       # 使用 XPath 提取产品标题的文本内容
       product_title = parser.xpath('//span[@id="productTitle"]/text()')[0].strip()

       # 打印提取的产品标题
       print({"Product Title": product_title})
   except IndexError:
       # 处理 XPath 查询不返回任何结果的情况
       print('Product title not found in the specified location.')
   except etree.XMLSyntaxError as parse_err:
       # 在解析过程中处理 XML 语法错误
       print(f'Error while parsing HTML: {parse_err}')
   except Exception as e:
       # 处理任何其他异常
       print(f'An unexpected error occurred: {e}')

   # 关闭浏览器上下文和浏览器
   context.close()
   browser.close()


# 使用 sync_playwright 启动 Playwright 会话并运行脚本
with sync_playwright() as playwright:
   run(playwright)

使用 Python 进行网络刮擦是一种从网站上获取数据的强大方法。所讨论的工具有助于提取、处理和存储用于各种目的的网络数据。在这一过程中,使用代理服务器交替 IP 地址和在请求之间实施延迟是规避拦截的关键。Beautiful Soup 对初学者来说非常友好,而 lxml 则因其高效性而适合处理大型数据集。对于更高级的刮擦需求,尤其是动态加载的 JavaScript 网站,Playwright 被证明是非常有效的。

评论:

0 评论