处理 2026 年网页抓取中的分页

分类: 48365平台 时间: 2025-12-24 10:46:34 作者: admin 阅读: 3993
处理 2026 年网页抓取中的分页

当你在抓取网页时,你经常会遇到分页的情况,即内容分布在多个页面上。处理这种分页可能具有挑战性,因为不同的网站使用不同的分页技术。

在本文中,我将解释常见的分页技术,并通过一个实用的代码示例展示如何处理它们。

什么是分页?

像电子商务平台、招聘网站和社交媒体等网站使用分页来管理大量数据。如果将所有内容显示在一个页面上,会显著增加加载时间并消耗过多内存。分页将内容分布在多个页面上,并提供诸如“下一页”、页码或滚动时自动加载的导航选项。这使得浏览更快、更有组织。

分页类型

分页的复杂性各不相同,从简单的数字分页到更高级的技术,如无限滚动或动态内容加载。根据我的经验,我遇到了三种主要的分页类型,我认为它们是网站上最常用的:

数字分页:用户通过数字链接导航到不同的页面。

点击加载分页:用户点击一个按钮(例如“加载更多”)来加载更多内容。

无限滚动:用户向下滚动页面时内容自动加载。

让我们更详细地探讨一下每种分页方式!

数字分页

这是最常见的分页技术,通常称为“下一页和上一页分页”、“箭头分页”或“基于 URL 的分页”。尽管名称不同,但核心思想相同——页面通过数字链接进行连接。你可以通过更改 URL 中的页码来导航。要知道何时停止分页,你可以检查“下一页”按钮是否被禁用或是否没有新数据可用。

通常看起来是这样的:

`让我们举个例子!我们将浏览网站 Scrapethesite 上的所有页面。该网站的分页栏共有 24 页。

你会注意到,当你点击“>>”按钮时,URL 会发生如下变化:

第一页:https://www.scrapethissite.com/pages/forms/

第二页:https://www.scrapethissite.com/pages/forms/?page_num=2

第三页:https://www.scrapethissite.com/pages/forms/?page_num=3

现在,看看这个“下一页”按钮的 HTML。它是一个带有 href 属性的锚标签(),链接到下一页。aria-label 属性显示“下一页”按钮仍然是活动的。当没有更多页面时,aria-label 将缺失,显示分页的结束。

让我们从编写一个基本的网页抓取器开始,导航这些页面。首先,通过安装所需的包来设置你的环境。有关使用 Python 进行网页抓取的详细指南,你可以查看深入的博客文章 这里。

pip install requests beautifulsoup4 lxml

以下是分页浏览每个页面的代码:

import requests

from bs4 import BeautifulSoup

base_url = "https://www.scrapethissite.com/pages/forms/?page_num="

# Start with page 1

page_num = 1

while True:

url = f"{base_url}{page_num}"

response = requests.get(url)

soup = BeautifulSoup(response.content, "lxml")

print(f"Currently on page: {page_num}")

# Check if 'Next' button exists

next_button = soup.find("a", {"aria-label": "Next"})

if next_button:

# Move to the next page

page_num += 1

else:

# No more pages, exit loop

print("Reached the last page.")

break

这段代码通过检查是否存在带有 aria-label="Next" 的“下一页”按钮来导航页面。如果按钮存在,它会增加 page_num 并使用更新后的 URL 发送新的请求。循环将继续,直到不再找到“下一页”按钮,表明已经到达最后一页。

运行代码,你会看到我们已成功浏览了所有页面。

一些网站的“下一页”按钮不会更改 URL,但仍在同一页面上加载新内容。在这种情况下,传统的网页抓取方法可能效果不佳。像 Selenium 或 Playwright 这样的工具更适合,因为它们可以与页面交互并模拟点击按钮等操作,以检索动态加载的内容。有关使用 Selenium 进行此类任务的更多信息,你可以阅读详细指南 这里。

当你尝试抓取 NGINX 博客页面时,你会遇到类似的情况。

让我们使用 Playwright 来处理动态加载的内容。如果你是 Playwright 新手,可以查看这个有用的 入门指南。

现在,在编写代码之前,运行以下命令在你的机器上设置 Playwright:

pip install playwright

playwright install

以下是代码:

import asyncio

from playwright.async_api import async_playwright

# Define an asynchronous function

async def scrape_nginx_blog():

async with async_playwright() as p:

# Launch a Chromium browser instance in headless mode

browser = await p.chromium.launch(headless=True)

page = await browser.new_page()

# Navigate to the NGINX blog page

await page.goto("https://www.f5.com/company/blog/nginx")

page_num = 1

while True:

print(f"Currently on page {page_num}")

# Locate the 'Next' button using a button locator with value "next"

next_button = page.locator('button[value="next"]')

# Check if the 'Next' button is enabled

if await next_button.is_enabled():

await next_button.click() # Click the 'Next' button to go to the next page

await page.wait_for_timeout(

2000

) # Wait for 2 seconds to allow new content to load

page_num += 1

else:

print("No more pages. Scraping finished.")

break # Exit the loop if no more pages are available

await browser.close() # Close the browser

# Run the asynchronous scraping function

asyncio.run(scrape_nginx_blog())

该代码使用异步 Playwright 浏览所有页面。它进入一个循环,检查“下一页”按钮是否存在。如果按钮被启用,它会点击以转到下一页并等待内容加载。这个过程会重复,直到没有更多页面可用。最后,抓取完成后,浏览器将被关闭。

运行代码,你会看到我们已成功浏览了所有页面。

点击加载分页

在许多网站上,你可能见过“加载更多”、“显示更多”或“查看更多”等按钮。这些都是点击加载分页的例子,通常用于现代网站。这些按钮通过 JavaScript 动态加载内容。这里的关键挑战是模拟用户交互——自动化点击按钮以加载更多内容的过程。

以 Bright Data 博客 部分为例。当你访问并向下滚动时,你会注意到一个“查看更多”按钮,点击它会加载博客文章。

你可以使用 Selenium 或 Playwright 等工具,通过反复点击“加载更多”按钮,直到没有更多内容可用,来自动化这个过程。让我们看看如何使用 Playwright 轻松处理这个问题。

import asyncio

from playwright.async_api import async_playwright

async def scrape_brightdata_blog():

async with async_playwright() as p:

# Launch a headless browser

browser = await p.chromium.launch(headless=True)

page = await browser.new_page()

# Navigate to the Bright Data blog

await page.goto("https://brightdata.com/blog")

page_num = 1

while True:

print(f"Currently on page {page_num}")

# Locate the "View More" button

view_more_button = page.locator("button.load_more_btn")

# Check if the button is visible and enabled

if (

await view_more_button.count() > 0

and await view_more_button.is_visible()

):

await view_more_button.click()

await page.wait_for_timeout(2000)

page_num += 1

else:

print("No more pages to load. Scraping finished.")

break

# Close the browser

await browser.close()

# Run the scraping function

asyncio.run(scrape_brightdata_blog())

该代码使用 CSS 选择器 button.load_more_btn 定位“查看更多”按钮。然后,它通过使用 count() > 0 和 is_visible() 检查按钮是否存在且可见。如果按钮可见,它使用 click() 方法与其交互,并等待 2 秒以允许新内容加载。这个过程在循环中重复,直到按钮不再可见。

运行代码,你会看到我们已成功浏览了所有页面。

我们已成功从 Bright Data 博客部分抓取了所有 52 页。这表明该网站共有 52 页,我们是在抓取过程后才发现的。然而,在抓取之前知道总页数是可能的。

要做到这一点,打开开发者工具,导航到“网络”选项卡,并通过选择“Fetch/XHR”来筛选请求。然后,再次点击“查看更多”按钮,你会注意到触发了一个 AJAX 请求。

点击这个请求并导航到“预览”部分,你会看到最大页数是 52。然后,前往“负载”部分,你会发现每页有 6 篇博客文章,我们当前在第 3 页。

这太棒了!

无限滚动分页

许多网站现在使用无限滚动,而不是“上一页/下一页”按钮,这通过消除点击多个页面的需求来改善用户体验。这种技术会在用户向下滚动时自动加载新内容。然而,它为网页抓取器带来了独特的挑战,因为它需要监控 DOM 变化和处理 AJAX 请求。

让我们举一个现实生活中的例子。当你访问 Nike 网站时,你会注意到鞋子在你向下滚动时会自动加载。每次滚动时,一个加载图标会短暂出现,转眼间,更多鞋子就会显示出来,如下图所示:

当你点击请求 (d9a5bc) 时,你可以在“响应”选项卡中找到当前页面的所有数据。

现在,要处理分页,你需要不断向下滚动页面,直到到达页面底部。随着滚动,浏览器会发出许多请求,但这些 Fetch/XHR 请求中只有一些会包含你需要的实际数据。

以下是处理分页并提取鞋子标题的代码:

import asyncio

from urllib.parse import parse_qs, urlparse

from playwright.async_api import async_playwright

async def scroll_to_bottom(page) -> None:

"""Scroll to the bottom of the page until no more content is loaded."""

last_height = await page.evaluate("document.body.scrollHeight")

scroll_count = 0

while True:

# Scroll down

await page.evaluate("window.scrollTo(0, document.body.scrollHeight);")

await asyncio.sleep(2) # Wait for new content to load

scroll_count += 1

print(f"Scroll iteration: {scroll_count}")

# Check if scroll height has changed

new_height = await page.evaluate("document.body.scrollHeight")

if new_height == last_height:

print("Reached the bottom of the page.")

break # Exit if no new content is loaded

last_height = new_height

async def extract_product_data(response, extracted_products) -> None:

"""Extract product data from the response."""

parsed_url = urlparse(response.url)

query_params = parse_qs(parsed_url.query)

if "queryType" in query_params and query_params["queryType"][0] == "PRODUCTS":

data = await response.json()

for grouping in data.get("productGroupings", []):

for product in grouping.get("products", []):

title = product.get("copy", {}).get("title")

extracted_products.append({"title": title})

async def scrape_shoes(target_url: str) -> None:

async with async_playwright() as playwright:

browser = await playwright.chromium.launch(headless=True)

page = await browser.new_page()

extracted_products = []

# Set up listener for product data responses

page.on(

"response",

lambda response: extract_product_data(

response, extracted_products),

)

# Navigate to the page and scroll to the bottom

print("Navigating to the page...")

await page.goto(target_url, wait_until="domcontentloaded")

await asyncio.sleep(2)

await scroll_to_bottom(page)

# Save product titles to a text file

with open("product_titles.txt", "w") as title_file:

for product in extracted_products:

title_file.write(product["title"] + "n")

print(f"Scraping completed!")

await browser.close()

if __name__ == "__main__":

asyncio.run(

scrape_shoes(

"https://www.nike.com/in/w/mens-running-shoes-37v7jznik1zy7ok")

)

在代码中,scroll_to_bottom 函数不断滚动到页面底部以加载更多内容。它首先记录当前的滚动高度,然后反复向下滚动。每次滚动后,它会检查新的滚动高度是否与最后记录的高度不同。如果高度保持不变,它会得出没有更多内容被加载的结论并退出循环。这种方法确保在抓取过程继续之前,所有可用的产品都已完全加载。

当你运行代码时,会发生以下情况:

代码成功执行后,将创建一个包含所有 Nike 鞋子标题的新文本文件。

分页中的挑战

在处理分页内容时,被 封锁 的风险增加,一些网站可能会在仅一页后就封锁你。例如,如果你试图 抓取 Glassdoor,你可能会遇到各种 网页抓取挑战,其中之一就是我所经历的 Cloudflare CAPTCHA 挑战。

让我们向 Glassdoor 页面发起请求,看看会发生什么。

import requests

url = "https://www.glassdoor.com/"

response = requests.get(url)

print(f"Status code: {response.status_code}")

结果是一个 403 状态码。

这表明 Glassdoor 已检测到你的请求来自机器人或抓取器,导致 CAPTCHA 挑战。如果你继续发送多个请求,你的 IP 可能会立即被封锁。

要绕过这些封锁并有效地提取所需数据,你可以使用 Python Requests 中的代理 来 避免 IP 封锁,或通过 轮换用户代理 模仿真实浏览器。然而,重要的是要注意,这些方法都不能保证避免高级机器人检测。

那么,最终的解决方案是什么?让我们接下来深入探讨一下!

集成 Bright Data 解决方案

Bright Data 是绕过复杂反机器人措施的优秀解决方案。它只需几行代码即可无缝集成到你的项目中,并提供一系列针对任何高级反机器人机制的解决方案。

其中一个解决方案是 网页抓取器 API,它通过自动处理 IP 轮换和 CAPTCHA 解决 简化了从任何网站提取数据。这使你能够专注于数据分析,而不是数据检索的复杂细节。

例如,在我们的案例中,当尝试绕过 Glassdoor 上的 CAPTCHA 时遇到了挑战。为了解决这个问题,你可以使用 Bright Data 的 Glassdoor 抓取器 API,它专门设计用于绕过这些障碍并无缝地从网站提取数据。

要开始使用 Glassdoor 抓取器 API,请按照以下步骤操作:

首先,创建一个账户。访问 Bright Data 网站,点击 开始免费试用,并按照注册说明操作。登录后,你将被重定向到你的 仪表板,在那里你将获得一些免费积分。

现在,进入 Web Scraper API 部分,在 B2B 数据类别下选择 Glassdoor。你会找到各种数据收集选项,例如通过 URL 收集公司信息或通过 URL 收集职位列表。

在“Glassdoor 公司概述信息”下,获取你的 API 令牌并复制你的数据集 ID(例如,gd_l7j0bx501ockwldaqf)。

现在,以下是一个简单的代码片段,展示如何通过提供 URL、API 令牌和数据集 ID 来提取公司数据。

import requests

import json

def trigger_dataset(api_token, dataset_id, company_url):

"""

Triggers a dataset using the BrightData API.

Args:

api_token (str): The API token for authentication.

dataset_id (str): The dataset ID to trigger.

company_url (str): The URL of the company page to analyze.

Returns:

dict: The JSON response from the API.

"""

headers = {

"Authorization": f"Bearer {api_token}",

"Content-Type": "application/json",

}

payload = json.dumps([{"url": company_url}])

response = requests.post(

"https://api.brightdata.com/datasets/v3/trigger",

headers=headers,

params={"dataset_id": dataset_id},

data=payload,

)

return response.json()

api_token = "API_Token"

dataset_id = "DATASET_ID"

company_url = "https://www.glassdoor.com/"

response_data = trigger_dataset(api_token, dataset_id, company_url)

print(response_data)

运行代码后,你将收到如下所示的快照 ID:

使用快照 ID 来检索公司的实际数据。在终端中运行以下命令。对于 Windows,使用:

curl.exe -H "Authorization: Bearer API_TOKEN"

"https://api.brightdata.com/datasets/v3/snapshot/s_m0v14wn11w6tcxfih8?format=json"

对于 Linux:

curl -H "Authorization: Bearer API_TOKEN"

"https://api.brightdata.com/datasets/v3/snapshot/s_m0v14wn11w6tcxfih8?format=json"

运行命令后,你将获得所需的数据。

就这么简单!

同样,你可以通过修改代码从 Glassdoor 提取各种类型的数据。我已经解释了一种方法,但还有五种其他方法。因此,我建议探索这些选项来抓取你想要的数据。每种方法都针对特定的数据需求,帮助你获取所需的精确数据。

结论

本文讨论了现代网站常用的各种分页方法,如数字分页、“加载更多”按钮和无限滚动。还提供了有效实施这些分页技术的代码示例。然而,尽管处理分页是网页抓取的一部分,但克服反机器人检测是一个重大挑战。

逃避高级反机器人检测可能相当复杂,且成功率各不相同。Bright Data 的工具提供了一种简化且具有成本效益的解决方案,包括 Web Unlocker、Scraping Browser 和 Web Scraper APIs,满足你所有的网页抓取需求。只需几行代码,你就可以实现更高的成功率,而无需麻烦地管理复杂的反机器人措施。

完全不想参与抓取过程?看看我们的 数据集市场!

今天就注册,享受免费试用。

相关文章

巴拉圭的世界杯英雄:那些闪耀绿茵场的传奇球员与他们的故事
《少年三国志》红将获取全攻略 解锁顶级武将的秘诀
PowerPoint 中演示文稿的密码保护