网络数据采集与解析

在AI项目中,数据是驱动决策和优化产品的核心。许多数据需要通过网络采集,并做解析。掌握这些技术可以帮助AI产品经理从互联网和其他在线数据源中获取有价值的信息,这些信息对于市场分析、竞争情报、用户需求预测等都至关重要。

Python爬虫技术的基础知识

网络数据采集通常需要使用到爬虫技术。所谓“爬虫”是指一种自动化的程序,用于模拟浏览器访问网页并抓取网页上的数据。运用爬虫技术能够自动化地从网页中提取信息,节省人工收集数据的时间,并确保数据的准确性和实时性。

爬虫工作时通常需要发送HTTP或HTTPS请求,获取网页内容后再进行解析和数据提取。HTTP或HTTPS都是常见的网络协议。所谓网络协议是计算机网络中用于数据传输的规则和约定,它定义了不同设备之间如何交换信息。其中,HTTP(超文本传输协议)是最常见的协议之一,用于在浏览器和服务器之间传输网页数据。HTTPS(安全超文本传输协议)则是HTTP的加密版本,它通过SSL/TLS协议确保数据的安全性,防止在传输过程中被窃取或篡改。因此,HTTPS相比HTTP在数据传输过程中增加了加密保护,保证了信息的安全性,对于爬虫技术来说,爬取HTTPS网页时往往还需要额外处理证书和安全性问题。

通过HTTP或HTTPS协议,我们通常获取到的是网页。因此,我们要对网页的代码进行分析,以提取有用的信息。这被称为网页结构解析。它是网络数据采集的基础。网页的基础结构通常由三部分组成:HTML、CSS和JavaScript。HTML(超文本标记语言)用于定义网页的内容和结构,如标题、段落、图片等;CSS(层叠样式表)负责控制网页的外观,如字体、颜色、布局等;JavaScript则用于实现网页的动态交互功能,如按钮点击、数据更新等。它们的主要区别在于:HTML负责结构,CSS负责样式,JavaScript负责行为。在Python中,我们需要用不同的库去解析这些不同的网页内容。

首先,我们来看一下怎么处理HTML格式的文件,这里我们经常用到的是 BeautifulSoup 库。

BeautifulSoup 库

BeautifulSoup 是一个 Python 库,用于从网页的 HTML 或 XML 文档中提取数据。它能够解析网页并提供简单的方式来遍历、搜索和修改解析树。它特别适合用于 Web 爬虫和数据抓取,因为它能轻松地处理不规则的 HTML 页面,且具有强大的查找和筛选功能。

常见功能

  • 解析 HTML 和 XML 文档。
  • 方便的遍历 HTML 树结构。
  • 使用 CSS 选择器或 XPath 方式提取特定数据。
  • 可以提取文本、链接、属性等。

以下是一个简单的代码示例,您可以学习如何使用BeautifulSoup来遍历HTML树结构,并精准提取所需信息。

要提取网页的 Html 代码:

<html>
    <body>
        <div class="article-list">
            <div class="article">
                <a href="https://example.com/article1">文章一</a>
            </div>
            <div class="article">
                <a href="https://example.com/article2">文章二</a>
            </div>
            <div class="article">
                <a href="https://example.com/article3">文章三</a>
            </div>
        </div>
    </body>
</html>

示例代码:

from bs4 import BeautifulSoup

# 示例 HTML 页面(通常是通过网络请求获取的网页内容)
html_content = """
<html>
    <body>
        <div class="article-list">
            <div class="article">
                <a href="https://example.com/article1">文章一</a>
            </div>
            <div class="article">
                <a href="https://example.com/article2">文章二</a>
            </div>
            <div class="article">
                <a href="https://example.com/article3">文章三</a>
            </div>
        </div>
    </body>
</html>
"""

# 使用 BeautifulSoup 解析 HTML 内容
soup = BeautifulSoup(html_content, 'html.parser')

# 遍历所有文章(通过 class 属性定位)
articles = soup.find_all('div', class_='article')

# 提取标题和链接
for article in articles:
    title = article.find('a').text  # 提取文章标题(文本)
    link = article.find('a')['href']  # 提取文章链接(href 属性)
    print(f"标题: {title}, 链接: {link}")

代码说明:

  • BeautifulSoup(html_content, 'html.parser'):这行代码将 HTML 内容传递给 BeautifulSoup,使用 Python 内置的解析器来解析。
  • soup.find_all('div', class_='article'):使用 find_all 方法查找所有 <div> 元素,且其 class 属性为 'article'。这个方法返回一个列表,包含所有符合条件的元素。
  • article.find('a').text:在每个文章的 <div> 标签中,找到 <a> 标签并提取其文本内容,也就是文章的标题。
  • article.find('a')['href']:在每个文章的 <a> 标签中,提取 href 属性,这就是文章的链接。

提示词示例:

提示词:

请编写一段 Python 代码,使用 BeautifulSoup 库来解析一个简单的 HTML 页面,并从中提取所有包含在 <div class="article"> 标签中的文章标题和对应的链接。目标是遍历这些文章元素,并提取其中 <a> 标签的文本内容(即文章标题)以及 href 属性(即文章链接)。请确保以下几点:

  1. HTML 页面是一个多篇文章的列表,每篇文章都有一个标题和链接。
  2. 使用 BeautifulSoup 解析 HTML 内容。
  3. 使用 find_all 方法获取所有符合条件的 div 标签(带有 class="article")。
  4. 使用 find 方法提取每篇文章的标题(a 标签的文本内容)和链接(a 标签的 href 属性)。 打印每篇文章的标题和链接。

输出格式应该是每篇文章的标题和链接一行,形式如下:

<example>
标题: 文章标题, 链接: 文章链接
</example>

XPath库

XPath(XML Path Language)是一种用于在 XML 文档中查找信息的语言。在处理 HTML 和 XML 文档时,XPath 是非常强大的工具,能够根据元素的结构、属性、文本等进行精确定位。与 BeautifulSoup 类似,XPath可以帮助我们通过路径表达式来定位网页中的特定元素。Python 中常用的 XPath 库是 lxml,它支持高效的 XPath 查询。

常见功能

  • 支持在 HTML 和 XML 文档中根据标签名称、属性、位置、文本内容等查找节点。
  • 可以使用路径表达式(如 /html/body/div)精确定位元素。
  • 支持复杂的查询和筛选条件,例如查找含有特定文本的标签。

下面我们看一个使用XPath定位网页元素的代码示例:我们有一个简单的 HTML 页面,其中包含多个文章的标题和链接。我们希望通过 XPath 定位每篇文章的 <a> 标签,并提取其文本内容和 href 属性。

要提取网页的 Html 代码:

<html>
    <body>
        <div class="article-list">
            <div class="article">
                <a href="https://example.com/article1">文章一</a>
            </div>
            <div class="article">
                <a href="https://example.com/article2">文章二</a>
            </div>
            <div class="article">
                <a href="https://example.com/article3">文章三</a>
            </div>
        </div>
    </body>
</html>

目标:提取每篇文章的标题和链接。

示例代码:

from lxml import etree

# 示例 HTML 页面
html_content = """
<html>
    <body>
        <div class="article-list">
            <div class="article">
                <a href="https://example.com/article1">文章一</a>
            </div>
            <div class="article">
                <a href="https://example.com/article2">文章二</a>
            </div>
            <div class="article">
                <a href="https://example.com/article3">文章三</a>
            </div>
        </div>
    </body>
</html>
"""

# 使用 lxml 库解析 HTML 内容
tree = etree.HTML(html_content)

# 使用 XPath 定位所有文章链接
articles = tree.xpath('//div[@class="article"]/a')

# 提取标题和链接
for article in articles:
    title = article.text  # 提取文章标题(文本)
    link = article.get('href')  # 提取文章链接(href 属性)
    print(f"标题: {title}, 链接: {link}")

代码说明:

  • etree.HTML(html_content):通过 lxml 库的 HTML 函数将 HTML 内容解析为一个树结构。
  • tree.xpath('//div[@class="article"]/a'):使用 XPath 表达式,定位所有 <div class="article"> 内的 <a> 标签。XPath 表达式 //div[@class="article"]/a 意味着选择所有 classarticle<div> 元素下的 <a> 标签。
  • article.text:提取 <a> 标签内的文本内容,即文章的标题。
  • article.get('href'):提取 <a> 标签的 href 属性,即文章的链接。

提示词示例:

提示词:

请编写一段 Python 代码,使用 lxml 库和 XPath 定位从 HTML 页面中提取每篇文章的标题和链接。要求如下:

  1. 页面包含多个文章列表,每篇文章都有一个标题和链接。
  2. 使用 lxml 库解析 HTML 内容并生成树形结构。
  3. 使用 XPath 表达式 //div[@class="article"]/a 定位到每篇文章的 <a> 标签。
  4. 提取每个 <a> 标签中的标题(文本内容)和链接(href 属性)。
  5. 将每篇文章的标题和链接打印出来,格式为:

<example>
标题: 文章标题, 链接: 文章链接
</example>

使用正则表达式提取复杂文本

正则表达式是一种强大的文本处理工具,用于描述、匹配和提取字符串中的特定模式。它非常适合用于从混合文本中提取关键信息,例如电话号码、价格、日期等。在 Python 中,我们使用内置的 re 模块来编写和执行正则表达式,从而高效地处理和解析网页上的复杂文本数据。

如何编写正则表达式来匹配特定模式?

正则表达式通过一些特殊符号描述字符模式,例如:

  • \d 表示任意数字(0-9)。
  • + 表示前面的字符或表达式出现一次或多次。
  • \. 表示匹配字面意义上的点号(.)。
  • {2} 表示前面的字符或表达式恰好出现两次。

例如,要匹配人民币价格格式(如“¥99.99”),我们可以使用正则表达式 r"¥\d+\.\d{2}"

  • :匹配人民币符号。
  • \d+:匹配一个或多个数字。
  • \.:匹配小数点。
  • \d{2}:匹配恰好两位数字。

假设我们从网页上获取到一段包含促销信息的文本,其中嵌入了多个产品价格,格式为“¥数字.两位小数”(例如:¥99.99)。我们的目标是使用正则表达式提取出所有这些价格信息。下面是一个示例:

示例代码:

import re

# 示例文本(通常从网页中提取)
text = """
最新促销信息:产品A售价为¥99.99,产品B售价为¥149.99,产品C售价为¥79.99。
此外,购买满200元可享受额外折扣。联系方式:123-456-7890。
"""

# 编写正则表达式来匹配价格(格式:¥后跟数字、小数点和两位数字)
pattern = r"¥\d+\.\d{2}"

# 使用 re.findall 方法提取所有匹配的价格
prices = re.findall(pattern, text)

# 输出提取的价格
print("提取的价格:", prices)

代码说明

  • import re:导入 Python 内置的正则表达式模块。
  • text:包含促销信息的示例文本,内含多个产品价格及其他信息。
  • pattern = r"¥\d+\.\d{2}":定义了一个正则表达式,用于匹配价格格式:
    • 匹配人民币符号。
    • \d+ 匹配一个或多个数字。
    • \. 匹配字面的小数点。
    • \d{2} 匹配恰好两位数字。
  • re.findall(pattern, text):扫描整个文本,返回所有匹配该正则表达式的字符串列表。
  • print("提取的价格:", prices):将提取的价格信息打印输出。

提示词示例:

提示词:

请编写一段 Python 代码,使用 re 模块和正则表达式从包含促销信息的文本中提取产品价格。要求如下:

  1. 文本中包含多个产品价格,价格格式为“¥数字.两位小数”(例如:¥99.99)。
  2. 使用正则表达式 r"¥\d+\.\d{2}" 匹配所有价格。
  3. 使用 re.findall 方法提取匹配的价格,并打印输出,格式为:

<example>
提取的价格: [价格1, 价格2, ...]
</example>

使用 Selenium 捕获动态加载数据 Selenium 是一个用于 Web 自动化测试的开源工具,它可以模拟真实浏览器的行为。通过 Selenium,我们可以加载整个网页、执行 JavaScript、模拟用户操作(如点击、输入等),从而捕获网页中动态加载的数据。对于需要处理 JavaScript 动态渲染内容的爬虫任务,Selenium 是一个非常实用的工具。 如何使用 Selenium? 使用 Selenium 主要包括以下步骤:
  • 安装 Selenium:通过 pip 安装 Selenium 模块。
  • 配置浏览器驱动:下载对应浏览器的驱动程序(如 ChromeDriver)并配置好路径。
  • 创建 WebDriver 实例:通过 WebDriver 控制浏览器(可以选择无头模式以实现无界面运行)。
  • 加载目标网页:使用 get 方法打开网页。
  • 等待动态内容加载:可通过固定时间等待或显式等待方式确保动态数据加载完成。
  • 定位并提取数据:通过各种定位方式(如 ID、CSS 选择器、XPath 等)提取页面中动态生成的数据。
  • 关闭浏览器:完成数据提取后,关闭 WebDriver。
假设我们需要采集一个动态加载数据的网页,该网页通过 JavaScript 渲染了一个数据容器,其 ID 为 “data-container”,容器中包含了我们所需要的关键信息。我们将使用 Selenium 来模拟真实浏览器的加载过程,捕获这个动态数据。下面提供了一个开发示例:

示例代码:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
import time

# 配置 Chrome 选项,例如启用无头模式(不显示浏览器窗口)
chrome_options = Options()
chrome_options.add_argument("--headless")  # 如果需要无头运行,可以启用此选项

# 指定 ChromeDriver 路径(请替换为你本地实际的 ChromeDriver 路径)
driver_path = "path/to/chromedriver"

# 创建 WebDriver 实例
service = Service(driver_path)
driver = webdriver.Chrome(service=service, options=chrome_options)

# 打开目标网页
driver.get("https://example.com/dynamic-page")

# 等待页面加载完成(实际使用时可考虑使用显式等待)
time.sleep(3)

# 定位动态加载的数据元素(例如:id 为 "data-container" 的元素)
data_element = driver.find_element(By.ID, "data-container")
data_text = data_element.text

print("动态加载的数据:", data_text)

# 关闭浏览器
driver.quit()

代码说明

  • 导入必要模块:使用 selenium.webdriver 相关模块创建浏览器驱动;time 模块用于简单等待。
  • Chrome 选项配置:使用 Options 配置 Chrome 为无头模式,这样运行时不会弹出浏览器窗口。
  • 创建 WebDriver 实例:通过指定 ChromeDriver 路径和选项,创建控制浏览器的实例。
  • 加载网页driver.get() 方法加载目标网页(示例中为 https://example.com/dynamic-page)。
  • 等待加载:使用 time.sleep(3) 等待 3 秒,确保 JavaScript 动态数据加载完成。实际开发中可考虑使用 Selenium 的显式等待(例如 WebDriverWait)。
  • 数据定位与提取:通过 find_element(By.ID, "data-container") 定位到包含动态数据的元素,并提取其文本内容。
  • 关闭浏览器:调用 driver.quit() 关闭浏览器,释放资源。

提示词示例:

提示词:

请编写一段 Python 代码,使用 Selenium 来模拟真实浏览器的行为,以捕获一个动态加载数据的网页中的关键信息。要求如下:

  1. 使用 Selenium 控制 Chrome 浏览器,并启用无头模式。
  2. 指定 ChromeDriver 路径,并创建 WebDriver 实例。
  3. 打开一个动态加载数据的示例网页(例如 https://example.com/dynamic-page)。
  4. 等待足够时间(或使用显式等待)确保页面中 JavaScript 渲染的数据加载完成。
  5. 定位页面中 id 为 "data-container" 的元素,并提取其中的文本数据。
  6. 打印出提取到的数据,并在最后关闭浏览器。

在抓取网页时,处理网页编码问题也十分关键,尤其是遇到中文或其他非ASCII字符时容易出现乱码。通常可以通过检查响应头或使用 chardet 自动检测编码,并在获取网页内容后显式设置正确编码,例如使用 requests 库时可以这样操作:response = requests.get(url); response.encoding = 'utf-8',然后再用 BeautifulSoup(response.text, 'html.parser') 进行解析,以确保数据能被正确解码和处理。

此外,在抓取网页时,为了更好地模拟真实浏览器的访问行为,可以在 HTTP 请求中设置合适的 User-Agent 和 Cookie 信息,这样有助于绕过部分反爬虫机制。例如,使用 Python 的 requests 库时,可以通过构造自定义请求头来实现这一点,如下示例所示:

示例代码:

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
    'Cookie': 'sessionid=abc123; token=xyz'
}

response = requests.get('https://example.com', headers=headers)
print(response.text)

这种方式可以使请求看起来更像是真实的浏览器访问,从而提高数据抓取的成功率。

爬虫技术的合规性问题

尤其要重视和注意的是:在使用爬虫技术时,必须严格遵守相关法律法规(如《网络安全法》《著作权法》等),同时注重伦理道德责任。爬虫行为应尊重目标网站的 robots.txt 文件和服务条款,避免在未获授权情况下大规模抓取数据,从而侵犯网站的知识产权或用户隐私。尤其对于中小型网站,即便它们没有明确限制爬虫访问,但其服务器配置可能较低,高并发的请求可能导致服务器崩溃或性能下降,给网站运营带来不必要的负担。因此,在设计爬虫时,应合理设置抓取速率和请求间隔,必要时与网站管理员取得沟通和许可,以确保数据采集既合法合规,又不会对目标网站造成负面影响。

最后,我们看一个综合实例。在这个案例中,我们需要从一个中文电子商务网站采集产品信息,生成产品列表报告(例如CSV或Excel),便于后续数据分析和决策支持。

提示词示例:

提示词:

请编写一个 Python 脚本,用于从一个中文电子商务网站采集产品信息并生成报告。要求如下:

  1. 使用 requests 发送 HTTP 请求获取网页内容,确保处理中文编码问题。
  2. 利用 BeautifulSoup 解析HTML文档,定位每个产品的容器(例如 <div class="product-item">),并提取产品名称(例如 <h2 class="product-name">)、价格(例如 <span class="product-price">)和描述(例如 <p class="product-desc">)。
  3. 使用正则表达式从价格字符串中提取数字,并将其转换为浮点数。
  4. 如果产品描述为空,使用 Selenium 模拟浏览器操作,打开产品详情页面(假设详情链接在 <a class="details-link"> 中),等待动态加载后从指定元素(例如 class="product-full-desc")中提取完整描述。
  5. 将所有提取到的产品数据整合成一个 Pandas DataFrame,并保存为 CSV 文件 "product_report.csv"。
  6. 在整个过程中加入异常处理,确保在请求、解析、动态加载及文件保存过程中出现错误时输出详细的错误信息。

示例代码:

import requests
import re
import time
import pandas as pd
from bs4 import BeautifulSoup

# --- Step 1: 使用 requests 获取网页内容 ---
url = "https://www.example-chinese-ecommerce.com/products"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
}

try:
    response = requests.get(url, headers=headers)
    # 处理中文编码问题
    response.encoding = 'utf-8'
    html_content = response.text
    print("成功获取网页内容。")
except Exception as e:
    print(f"请求网页内容时发生错误:{e}")
    exit(1)

# --- Step 2: 利用 BeautifulSoup 解析HTML并提取静态数据 ---
soup = BeautifulSoup(html_content, "html.parser")
# 假设每个产品信息位于 <div class="product-item"> 标签中
product_items = soup.find_all("div", class_="product-item")
products = []

for item in product_items:
    try:
        name = item.find("h2", class_="product-name").get_text(strip=True)
        price_text = item.find("span", class_="product-price").get_text(strip=True)
        # 使用正则表达式提取价格数字,假设价格格式为“价格:¥199.99”
        price_match = re.search(r"¥([\d\.]+)", price_text)
        price = float(price_match.group(1)) if price_match else None
        desc = item.find("p", class_="product-desc").get_text(strip=True) if item.find("p", class_="product-desc") else ""
        
        product = {"name": name, "price": price, "desc": desc}
        products.append(product)
    except Exception as e:
        print(f"提取产品信息时发生错误:{e}")

# --- Step 3: 对动态加载的内容使用 Selenium 补充数据 ---
# 如果发现某个产品描述为空,则尝试使用 Selenium 获取详细描述
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options

# 设置Chrome为无头模式
chrome_options = Options()
chrome_options.add_argument("--headless")
# 请替换为实际的ChromeDriver路径
driver = webdriver.Chrome(executable_path="path/to/chromedriver", options=chrome_options)

for product in products:
    if not product["desc"]:
        try:
            # 假设产品详情链接存在于 <a class="details-link"> 的 href 属性中
            details_link_tag = soup.find("a", class_="details-link")
            if details_link_tag and details_link_tag.get("href"):
                details_url = details_link_tag.get("href")
            else:
                details_url = url  # 如果找不到,则使用当前页面URL作为占位
            driver.get(details_url)
            time.sleep(3)  # 等待动态加载完成
            # 定位详细描述的元素(假设其class为 "product-full-desc")
            desc_element = driver.find_element(By.CLASS_NAME, "product-full-desc")
            product["desc"] = desc_element.text.strip()
            print(f"成功补充产品 {product['name']} 的详细描述。")
        except Exception as e:
            print(f"使用Selenium获取产品详细描述时出错:{e}")
driver.quit()

# --- Step 4: 整合数据并生成报告 ---
df = pd.DataFrame(products)
try:
    df.to_csv("product_report.csv", index=False, encoding='utf-8-sig')
    print("产品报告已成功保存为 'product_report.csv'。")
except Exception as e:
    print(f"保存报告时发生错误:{e}")
代码说明
  • 获取网页内容
    • 使用 requests.get() 向目标网站发送 HTTP 请求,并通过 response.encoding = 'utf-8' 确保中文内容正确显示。
  • 解析HTML并提取数据
    • 使用 BeautifulSoup 解析网页HTML,通过定位 <div class=”product-item”> 标签获取每个产品的信息。
    • 利用 find()get_text() 方法提取产品名称、价格和描述。
    • 对价格字段使用正则表达式提取数值部分,并将其转换为浮点数。
  • 处理动态加载的数据
    • 当某个产品描述为空时,利用 Selenium 启动无头浏览器,模拟用户访问产品详情页,等待动态内容加载后提取完整描述。
  • 生成报告
    • 将所有提取的数据整合为一个 Pandas DataFrame,并将其保存为 CSV 文件,便于后续分析和决策支持。

练习:

请尝试设计提示词,或者直接在综合示例代码基础上做适当修改,使其完成下述任务:

选择一个真实且允许抓取数据的测试网站(例如可以使用 “http://quotes.toscrape.com” 或其他公开测试网站),或您在企业中有权限抓取的中文电商网站。确保您选择的网站内容结构与产品信息相关(如商品名称、价格、描述等),或者您可以将示例中的产品信息概念替换为目标网站中的其他信息(如名言、作者、标签等)。尝试用脚本抓取网页数据,并在此基础上将最终抓取到的数据整合为一个结构化的报告(如 CSV 文件)。请确保在每个步骤中都有适当的异常处理和日志记录。

AI 助教

提示:您可在此提出学习中遇到的问题。回答由 AI 生成,可能存在错误,请注意甄别。