杰瑞科技汇

Python如何采集WordPress网站数据?

我将为你提供一个全面、从入门到实践的指南,涵盖从简单到复杂的多种方法,并重点讲解如何处理 WordPress 的动态加载内容。

Python如何采集WordPress网站数据?-图1
(图片来源网络,侵删)

目录

  1. 准备工作
    • 安装必要的 Python 库
    • 理解 WordPress 的基本结构
  2. 使用 requests + BeautifulSoup (静态页面采集)
    • 原理
    • 代码示例
    • 优缺点分析
  3. 使用 selenium (动态页面采集)
    • 原理
    • 安装与配置
    • 代码示例
    • 优缺点分析
  4. 高级技巧与最佳实践
    • 处理分页
    • 设置请求头模拟浏览器
    • 处理反爬机制
    • 使用代理 IP
    • 数据存储
  5. 一个完整的实战案例
    • 目标:采集一个 WordPress 博客的所有文章标题、链接、摘要和发布日期。
    • 代码实现 (使用 requests + BeautifulSoup)
  6. 重要提醒:法律与道德规范

准备工作

安装必要的 Python 库

你需要安装几个核心库来帮助你完成采集任务。

# 用于发送 HTTP 请求,获取网页内容
pip install requests
# 用于解析 HTML 和 XML 文档,提取数据
pip install beautifulsoup4
# 可选,用于处理数据,特别是表格数据
pip install pandas
# 可选,用于动态页面采集
pip install selenium
# 可选,用于处理 JavaScript 渲染的页面(是 Selenium 的替代品,更现代)
pip install playwright

理解 WordPress 的基本结构

大多数 WordPress 网站的文章列表页面都有共同的特征:

  • 文章容器: 所有文章通常被包裹在一个具有特定 CSS 类的 <div><article> 标签中,常见的类名有 post, entry, hentry, type-post 等。
  • : 文章标题通常在 <h2>, <h3><h1> 标签内,并且链接到文章详情页 (<a> 标签)。
  • 文章摘要: 文章的摘要或部分内容可能在 <p> 标签内,或者位于一个特定的 div.excerpt 中。
  • 发布日期: 发布日期通常在 <time> 标签或一个带有 date 类的 <span> 标签中。
  • 分页: 分页通常通过 "Older Posts" / "Newer Posts" 链接实现,或者使用 "Load More" 按钮以及 AJAX 无限滚动。

开发者工具是你的好朋友:在浏览器中按 F12 打开开发者工具,选择 "Elements" (元素) 面板,然后点击 "Select an element in the page to inspect it" (选择页面元素以检查) 按钮,点击你想要采集的内容(如一篇文章标题),这样你就能精确地看到它的 HTML 结构和 CSS 类名。


方法一:使用 requests + BeautifulSoup (静态页面)

这种方法适用于在服务器端就已经生成好,直接返回给浏览器的 WordPress 网站,这是最快、最轻量级的方法。

Python如何采集WordPress网站数据?-图2
(图片来源网络,侵删)

原理

  1. requests 库向目标 WordPress 网站的 URL 发送一个 HTTP GET 请求。
  2. 服务器返回 HTML 页面的源代码。
  3. BeautifulSoup 将 HTML 源代码解析成一个对象,方便我们通过标签、类名等来定位和提取数据。

代码示例

假设我们要采集 https://wordpress.org/news/ 的文章标题和链接。

import requests
from bs4 import BeautifulSoup
import time
# 目标 URL
url = 'https://wordpress.org/news/'
# 设置请求头,模拟浏览器访问
# 有些网站会拒绝没有 User-Agent 的请求
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'
}
try:
    # 1. 发送请求
    response = requests.get(url, headers=headers, timeout=10)
    # 如果请求失败 (404, 500),抛出异常
    response.raise_for_status() 
    # 2. 解析 HTML
    soup = BeautifulSoup(response.text, 'html.parser')
    # 3. 定位数据容器 (通过检查元素找到的类名)
    # 在 wordpress.org/news 中,文章在 'post' 类的 div 中
    posts = soup.find_all('div', class_='post')
    if not posts:
        print("没有找到文章容器,请检查 HTML 结构是否变化。")
    else:
        # 4. 遍历并提取数据
        for post in posts:
            # 提取标题 (在 h2 标签的 a 标签里)
            title_tag = post.find('h2', class_='post-title')
            if title_tag:
                title = title_tag.get_text(strip=True)
                link = title_tag.find('a')['href']
                print(f"标题: {title}")
                print(f"链接: {link}")
                print("-" * 30)
    # 礼貌性暂停,避免对服务器造成过大压力
    time.sleep(1)
except requests.exceptions.RequestException as e:
    print(f"请求失败: {e}")

优缺点分析

  • 优点:
    • 速度快,资源消耗低。
    • 代码简单,易于理解和实现。
  • 缺点:
    • 无法处理由 JavaScript 动态加载的内容(点击 "Load More" 按钮后出现的新文章)。
    • 容易被简单的反爬机制识别。

方法二:使用 selenium (动态页面)

WordPress 网站使用了 AJAX、无限滚动或 "Load More" 按钮来动态加载文章,requests 就无能为力了,这时我们需要一个能控制浏览器、执行 JavaScript 的工具,selenium 是最经典的选择。

原理

  1. selenium 启动一个真实的浏览器(如 Chrome, Firefox)。
  2. 通过代码控制这个浏览器打开目标网页。
  3. 等待页面上的 JavaScript 执行完毕,动态内容加载出来。
  4. 获取浏览器当前页面的完整 HTML 源代码。
  5. 将 HTML 源代码交给 BeautifulSoup 进行解析和数据提取。

安装与配置

  1. 安装 selenium 库 (pip install selenium)。
  2. 下载对应浏览器的 WebDriver,如果你使用 Chrome 浏览器,需要下载 ChromeDriver
    • ChromeDriver 下载地址: https://googlechromelabs.github.io/chrome-for-testing/
    • 确保 WebDriver 的版本与你的 Chrome 浏览器版本大致匹配
    • 下载后,将 chromedriver.exe (Windows) 或 chromedriver (Mac/Linux) 放在你的项目目录下,或者系统 PATH 路径中。

代码示例

假设我们要采集一个使用 "Load More" 按钮加载文章的 WordPress 网站。

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
from bs4 import BeautifulSoup
import time
# --- 配置 Selenium ---
# ChromeDriver 的路径 (如果你把它放在了项目根目录下)
# CHROME_DRIVER_PATH = './chromedriver' 
# 如果在系统PATH中,可以不指定路径
# 设置 Chrome 选项
chrome_options = Options()
# chrome_options.add_argument('--headless')  # 无头模式,不显示浏览器窗口
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--no-sandbox')
# 初始化 WebDriver
# service = Service(executable_path=CHROME_DRIVER_PATH)
# driver = webdriver.Chrome(service=service, options=chrome_options)
# 如果chromedriver在PATH中,可以这样写
driver = webdriver.Chrome(options=chrome_options)
url = 'https://example.com/a-wordpress-site-with-load-more/' # 替换成你的目标网站
try:
    # 1. 打开网页
    driver.get(url)
    # 2. 循环点击 "Load More" 按钮,直到没有更多内容
    while True:
        try:
            # 尝试找到 "Load More" 按钮 (类名可能需要根据实际情况修改)
            load_more_button = driver.find_element(By.CSS_SELECTOR, '.load-more-button-class')
            print("找到 'Load More' 按钮,点击中...")
            load_more_button.click()
            # 等待新内容加载
            time.sleep(2) 
        except:
            # 如果找不到按钮,说明已经加载完毕
            print("未找到 'Load More' 按钮,所有内容已加载完毕。")
            break
    # 3. 获取页面源代码
    page_source = driver.page_source
    # 4. 使用 BeautifulSoup 解析
    soup = BeautifulSoup(page_source, 'html.parser')
    # 5. 提取数据 (这里的解析逻辑和方法一相同)
    posts = soup.find_all('article', class_='post') # 假设文章在 article.post 中
    for post in posts:
        title_tag = post.find('h2', class_='entry-title')
        if title_tag:
            title = title_tag.get_text(strip=True)
            link = title_tag.find('a')['href']
            print(f"标题: {title}")
            print(f"链接: {link}")
            print("-" * 30)
finally:
    # 6. 关闭浏览器
    driver.quit()

优缺点分析

  • 优点:
    • 功能强大,可以处理任何由 JavaScript 渲染的动态内容。
    • 可以模拟用户交互(点击、输入、滚动等)。
  • 缺点:
    • 速度慢,资源消耗大(需要启动一个浏览器)。
    • 配置相对复杂(需要下载和管理 WebDriver)。
    • 代码更复杂。

高级技巧与最佳实践

处理分页

除了 "Load More",WordPress 还常用传统的分页链接。

Python如何采集WordPress网站数据?-图3
(图片来源网络,侵删)
  • 静态分页: URL 形如 .../page/2/, .../page/3/,你可以构造这些 URL,然后用 requests 循环请求。
    for page_num in range(1, 6): # 采集前5页
        url = f'https://example.com/blog/page/{page_num}/'
        # ... 发送请求和解析的代码 ...

设置请求头

如代码中所示,User-Agent 是最基本的请求头,可以让你看起来像一个正常的浏览器访问。Referer 也可以在某些情况下使用。

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',
    'Accept-Language': 'en-US,en;q=0.9',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
}

处理反爬机制

  • IP 封禁: 如果你请求太频繁,你的 IP 可能会被临时或永久封禁。
    • 解决方案: 设置 time.sleep(random.uniform(1, 3)) 在每次请求之间随机暂停,使用代理 IP 池
  • 验证码: 网站可能会弹出验证码。
    • 解决方案: selenium 可以手动处理,但自动化处理验证码(尤其是 reCAPTCHA v2)非常困难,通常需要第三方服务。

数据存储

采集到的数据最终需要存储起来。

  • CSV 文件: 适合存储结构化的表格数据。

    import csv
    with open('articles.csv', 'w', newline='', encoding='utf-8') as f:
        writer = csv.writer(f)
        writer.writerow(['标题', '链接', '#39;])
        for post in posts:
            # ... 提取数据 ...
            writer.writerow([title, link, excerpt])
  • JSON 文件: 灵活性高,适合存储嵌套或非结构化数据。

    import json
    data = []
    for post in posts:
        # ... 提取数据 ...
        data.append({'title': title, 'link': link, 'excerpt': excerpt})
    with open('articles.json', 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=4)
  • 数据库: 如果数据量巨大,需要频繁查询,应使用 MySQL, PostgreSQL 或 MongoDB 等数据库。


一个完整的实战案例

目标: 采集 https://quotes.toscrape.com/ (一个用来练习爬虫的网站,虽然不是WordPress,但结构类似) 的所有名言、作者和标签。

方法: 使用 requests + BeautifulSoup

import requests
from bs4 import BeautifulSoup
import csv
import time
base_url = 'http://quotes.toscrape.com/'
all_quotes_data = []
# 循环处理所有分页
while True:
    print(f"正在采集: {base_url}")
    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'}
    try:
        response = requests.get(base_url, headers=headers, timeout=10)
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        print(f"请求失败: {e}")
        break
    soup = BeautifulSoup(response.text, 'html.parser')
    # 1. 提取当前页面的名言
    quotes = soup.find_all('div', class_='quote')
    if not quotes:
        print("未找到名言,采集结束。")
        break
    for quote in quotes:
        text = quote.find('span', class_='text').get_text(strip=True)
        author = quote.find('small', class_='author').get_text(strip=True)
        tags = [tag.get_text(strip=True) for tag in quote.find_all('a', class_='tag')]
        all_quotes_data.append({
            'text': text,
            'author': author,
            'tags': ', '.join(tags)
        })
        print(f"已采集: {text[:30]}... by {author}")
    # 2. 寻找下一页链接
    next_button = soup.find('li', class_='next')
    if next_button:
        next_page_url = next_button.find('a')['href']
        # 构造完整的下一页 URL
        base_url = base_url.rstrip('/') + next_page_url
    else:
        # 如果没有下一页按钮,退出循环
        print("已到达最后一页。")
        break
    # 礼貌性暂停
    time.sleep(1)
# 3. 将数据保存到 CSV 文件
if all_quotes_data:
    with open('quotes.csv', 'w', newline='', encoding='utf-8') as f:
        writer = csv.DictWriter(f, fieldnames=['text', 'author', 'tags'])
        writer.writeheader()
        writer.writerows(all_quotes_data)
    print(f"\n采集完成!共采集 {len(all_quotes_data)} 条名言,已保存到 quotes.csv。")
else:
    print("\n未能采集到任何数据。")

重要提醒:法律与道德规范

在开始任何爬虫项目之前,请务必牢记以下几点:

  1. robots.txt 协议: 几乎所有网站都有一个 robots.txt 文件(https://example.com/robots.txt),它规定了哪些页面允许爬虫访问,哪些不允许。请务必遵守这个协议,使用 robotparser 模块可以检查你的爬虫是否被允许访问某个 URL。
  2. 服务条款: 仔细阅读目标网站的服务条款,很多网站明确禁止自动化采集。
  3. 频率限制: 不要对服务器造成过大压力,设置合理的请求间隔(time.sleep(1)),避免在短时间内发送大量请求。
  4. 数据所有权: 明确你采集的数据的版权和使用范围,不要将采集到的数据用于非法或商业用途,除非你获得了所有者的许可。
  5. 尊重隐私: 如果采集的数据涉及个人信息,请务必遵守相关隐私保护法律(如 GDPR, CCPA)。

requests 开始,如果遇到动态内容再升级到 seleniumplaywright,始终将道德和合法性放在第一位,祝你采集顺利!

分享:
扫描分享到社交APP
上一篇
下一篇