在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 属性(即文章链接)。请确保以下几点:
- HTML 页面是一个多篇文章的列表,每篇文章都有一个标题和链接。
- 使用 BeautifulSoup 解析 HTML 内容。
- 使用 find_all 方法获取所有符合条件的 div 标签(带有 class="article")。
- 使用 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意味着选择所有class为article的<div>元素下的<a>标签。article.text:提取<a>标签内的文本内容,即文章的标题。article.get('href'):提取<a>标签的href属性,即文章的链接。
提示词示例:
提示词:
请编写一段 Python 代码,使用 lxml 库和 XPath 定位从 HTML 页面中提取每篇文章的标题和链接。要求如下:
- 页面包含多个文章列表,每篇文章都有一个标题和链接。
- 使用 lxml 库解析 HTML 内容并生成树形结构。
- 使用 XPath 表达式 //div[@class="article"]/a 定位到每篇文章的 <a> 标签。
- 提取每个 <a> 标签中的标题(文本内容)和链接(href 属性)。
- 将每篇文章的标题和链接打印出来,格式为:
<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 模块和正则表达式从包含促销信息的文本中提取产品价格。要求如下:
- 文本中包含多个产品价格,价格格式为“¥数字.两位小数”(例如:¥99.99)。
- 使用正则表达式 r"¥\d+\.\d{2}" 匹配所有价格。
- 使用 re.findall 方法提取匹配的价格,并打印输出,格式为:
<example>
提取的价格: [价格1, 价格2, ...]
</example>
- 安装 Selenium:通过 pip 安装 Selenium 模块。
- 配置浏览器驱动:下载对应浏览器的驱动程序(如 ChromeDriver)并配置好路径。
- 创建 WebDriver 实例:通过 WebDriver 控制浏览器(可以选择无头模式以实现无界面运行)。
- 加载目标网页:使用
get方法打开网页。 - 等待动态内容加载:可通过固定时间等待或显式等待方式确保动态数据加载完成。
- 定位并提取数据:通过各种定位方式(如 ID、CSS 选择器、XPath 等)提取页面中动态生成的数据。
- 关闭浏览器:完成数据提取后,关闭 WebDriver。
示例代码:
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 来模拟真实浏览器的行为,以捕获一个动态加载数据的网页中的关键信息。要求如下:
- 使用 Selenium 控制 Chrome 浏览器,并启用无头模式。
- 指定 ChromeDriver 路径,并创建 WebDriver 实例。
- 打开一个动态加载数据的示例网页(例如 https://example.com/dynamic-page)。
- 等待足够时间(或使用显式等待)确保页面中 JavaScript 渲染的数据加载完成。
- 定位页面中 id 为 "data-container" 的元素,并提取其中的文本数据。
- 打印出提取到的数据,并在最后关闭浏览器。
在抓取网页时,处理网页编码问题也十分关键,尤其是遇到中文或其他非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 文件和服务条款,避免在未获授权情况下大规模抓取数据,从而侵犯网站的知识产权或用户隐私。尤其对于中小型网站,即便它们没有明确限制爬虫访问,但其服务器配置可能较低,高并发的请求可能导致服务器崩溃或性能下降,给网站运营带来不必要的负担。因此,在设计爬虫时,应合理设置抓取速率和请求间隔,必要时与网站管理员取得沟通和许可,以确保数据采集既合法合规,又不会对目标网站造成负面影响。
提示词示例:
提示词:
请编写一个 Python 脚本,用于从一个中文电子商务网站采集产品信息并生成报告。要求如下:
- 使用 requests 发送 HTTP 请求获取网页内容,确保处理中文编码问题。
- 利用 BeautifulSoup 解析HTML文档,定位每个产品的容器(例如 <div class="product-item">),并提取产品名称(例如 <h2 class="product-name">)、价格(例如 <span class="product-price">)和描述(例如 <p class="product-desc">)。
- 使用正则表达式从价格字符串中提取数字,并将其转换为浮点数。
- 如果产品描述为空,使用 Selenium 模拟浏览器操作,打开产品详情页面(假设详情链接在 <a class="details-link"> 中),等待动态加载后从指定元素(例如 class="product-full-desc")中提取完整描述。
- 将所有提取到的产品数据整合成一个 Pandas DataFrame,并保存为 CSV 文件 "product_report.csv"。
- 在整个过程中加入异常处理,确保在请求、解析、动态加载及文件保存过程中出现错误时输出详细的错误信息。
示例代码:
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 生成,可能存在错误,请注意甄别。
