踏入网页抓取的世界可能会让人感到有些不知所措。你需要选择合适的编程语言和库,还要应对许多意想不到的挫折。这一切很快就会让人应接不暇。但别因此而气馁! 在本文中,我解答了关于网页抓取的一些最常见的问题。你将了解到其他人的做法以及他们所面临的挑战,这将有助于指导你自己的决策过程。无论你是刚入行的新手还是经验丰富的老手,这里都有适合你的内容。
为什么我的爬虫无法获取与浏览器相同的数据?
你编写了脚本从网站抓取 HTML,却未能获取完整数据。你在浏览器中测试过选择器,它们应该能正常工作,对吧?事实并非总是如此。依赖 JavaScript 渲染的网站无法通过简单的 GET 请求正常工作。 Puppeteer 和 Selenium 等库会使用无头浏览器来渲染 JavaScript。它们允许你在浏览器环境中发起请求,并等待 JavaScript 执行完毕。这样,你就能获取完整的 HTML。你未必总需要无头浏览器来获取缺失的数据。试着在 HTML 中搜索 <script> 标签。缺失的数据可能作为 JavaScript 变量隐藏在 <script> 标签内。
如何抓取使用生成式 CSS 类的网站?
部分网站会使用库自动为不同页面组件生成唯一的类名。这会导致难以使用传统的 CSS 选择器定位特定元素。
一种解决方案是改用 XPath 表达式。XPath 选择器依赖于页面的布局,而非具体的类名。这意味着即使类名发生变化,XPath 选择器仍能定位到目标元素。
例如,假设有一个 HTML 组件如下所示:
<div class="container">
<div class="subcontainer_af21">
<ul class="ul_ax1">
<li class="li_adef">
<a href="https://link1">Winter Storm</a>
</li>
</ul>
<ul class="ul_cgt4">
<li class="li_ocv2">
<a href="https://lin2">SpaceX</a>
</li>
</ul>
</div>
</div>你可以使用以下代码选中第二个 <a> 元素:
//div[@class='container']/div/ul[2]/li/a
Cheerio 比 Puppeteer 更快吗?
是的,Cheerio 通常被认为比 Puppeteer 更快。这是因为 Cheerio 是一个服务器端库,直接处理 HTML 内容。而 Puppeteer 是一个浏览器自动化库,通过控制无头浏览器来加载网页并进行交互。Cheerio 的局限性在于它只能处理静态页面,不具备像 Puppeteer 那样与浏览器交互的能力
XPath 选择器比 CSS 选择器更好吗?
这取决于具体场景。若需根据元素的位置提取数据,XPath 是更优选择。但若需根据类名或 ID 等属性提取数据,CSS 选择器则更为合适。
Playwright 比 Puppeteer 更好吗?
两者功能相似,但 Playwright 支持多种浏览器,包括 Chrome、Firefox 和 Safari,而 Puppeteer 仅支持 Chrome 和 Chromium。
Playwright 在多标签页和多窗口操作方面支持更完善。它还内置了对浏览器上下文、Cookie 和存储的处理支持。Playwright 更适合复杂的项目。
如何避免 IP 被封禁?
通常,您可以尝试错开请求时间、使用不同 IP 地址、使用代理,或尝试修改浏览器指纹。对大多数人来说,这是一场永无止境的战斗。好消息是,情况不必如此。 您可以使用我们的解决方案——WebScrapingAPI。WebScrapingAPI 提供了一个 API,将为您处理所有繁重的工作。它能够执行 JavaScript、轮换代理,甚至处理 CAPTCHA。您再也不必担心 IP 被封禁。但别光听我们说,您可以免费试用。
如何使用 BeautifulSoup 从 HTML 中提取文本?
您可以使用 BeautifulSoup 库。以下是使用 .get_text() 函数提取文本的示例:
from bs4 import BeautifulSoup
html_doc = """
<html>
<head>
<title>title of the page</title>
</head>
<body>
<p>a paragraph</p>
<a href='https://link.com'>a link</a>
</body>
</html>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
paragraph_text = soup.find('p').text
print(paragraph_text)
#Prints 'a paragraph'
link_text = soup.find('a').text
print(link_text)
#Prints 'a link'
all_text = soup.get_text()
print(all_text)
"""
title of the page
a paragraph
a link
"""如何使用 Selenium 从 HTML 中提取文本?
以下是在 Selenium 中实现的方法:
from selenium import webdriver
from selenium.webdriver.common.by import By
DRIVER_PATH = 'path/to/chromedriver'
driver = webdriver.Chrome(executable_path=DRIVER_PATH)
driver.get("https://en.wikipedia.org/wiki/Main_Page")
# get all the h2 elements
content = driver.find_element(By.TAG_NAME, "h2")
print(content.text)# Prints 'From today's featured article'
如何使用 BeautifulSoup 根据文本选择 HTML 元素?
在 BeautifulSoup 中,您可以使用 soup.find 方法,并传入 text=re.compile("<text>") 参数:
from bs4 import BeautifulSoup
import re
html_doc = """
<html>
<body>
<p class="my_paragraph">a paragraph.</p>
<p class="my_paragraph">another paragraph.</p>
</body>
</html>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
# find the first pTag that contains the text 'a par'
pTag = soup.find("p", text=re.compile("a par"))
print(pTag)如何使用 Selenium 根据文本选择 HTML 元素?
在 Selenium 中,您可以通过 XPath 实现:
from selenium import webdriver
from selenium.webdriver.common.by import By
DRIVER_PATH = 'path/to/chromedriver'
driver = webdriver.Chrome(executable_path=DRIVER_PATH)
driver.get("https://en.wikipedia.org/wiki/Main_Page")
# get all the elements with class vector-body
span = driver.find_element(By.XPATH, "//span[contains(text(), 'Did')]")
print(span.text)
# Prints 'Did you know ...'driver.quit()
如何在 BeautifulSoup 中使用 CSS 选择器查找 HTML 元素?
以下是使用 BeautifulSoup 的 find 和 find_all 方法实现的方法:
from bs4 import BeautifulSoup
html_doc = """
<html>
<body>
<p class="my_paragraph">First paragraph.</p>
<p class="my_paragraph">Second paragraph..</p>
<p>Last paragraph.</p>
</body>
</html>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
# find all elements with class 'my_paragraph
elements = soup.find_all(class_="my_paragraph")
for element in elements:
print(element.text)
# prints 'First paragraph.' and 'Second paragraph..'如何使用 Selenium 根据类名查找 HTML 元素?
以下是使用 Selenium 实现的方法:
from selenium import webdriver
from selenium.webdriver.common.by import By
DRIVER_PATH = 'path/to/chromedriver'
driver = webdriver.Chrome(executable_path=DRIVER_PATH)
driver.get("https://en.wikipedia.org/wiki/Main_Page")
# get all the elements with class vector-body
elements = driver.find_elements(By.CLASS_NAME, "vector-body")
for element in elements:
print(element.text)
driver.quit()如何在 BeautifulSoup 中使用 XPath?
你需要 lxml Python 库:
import requests
from bs4 import BeautifulSoup
from lxml import etree
response = requests.get("https://en.wikipedia.org/wiki/Main_Page")
soup = BeautifulSoup(response.content, 'html.parser')
dom = etree.HTML(str(body))
xpath_str = '//h1//text()'
print(dom.xpath(xpath_str))
#Prints ['Main Page', 'Welcome to ', 'Wikipedia']
如何在 Selenium 中等待页面加载?
如果您只是想在查找任何元素时等待一定时间(超过该时间则超时),可以使用 driver.implicitly_wait(time_in_seconds) 函数:
from selenium import webdriver
from selenium.webdriver.common.by import By
DRIVER_PATH = 'C:/Users/Michael/Desktop/chromedriver'
driver = webdriver.Chrome(executable_path=DRIVER_PATH)
driver.implicitly_wait(10)
driver.get("https://en.wikipedia.org/wiki/Main_Page")
element = driver.find_element(By.ID, "not_found_id")
# the element does not exist, but it waits 10 seconds for it
text = element.text
print(text)
# Close the browserdriver.quit()
您也可以选择等待直到满足特定条件:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
DRIVER_PATH = 'C:/Users/Michael/Desktop/chromedriver'
driver = webdriver.Chrome(executable_path=DRIVER_PATH)
driver.get("https://en.wikipedia.org/wiki/Main_Page")
# Wait for the element with id 'content' to be present on the page
wait = WebDriverWait(driver, 10)
element = wait.until(EC.presence_of_element_located((By.ID, "content")))
element = driver.find_element(By.ID, "content")
text = element.text
print(text)
# Close the browserdriver.quit()
如何在 Puppeteer 中使用 CSS 选择器查找 HTML 元素?
在 Puppeteer 中,您可以使用 page.$() 和 page.$$() 函数通过 CSS 选择器选择元素。page.$() 函数用于查找第一个匹配选择器的元素,而 page.$$() 函数用于查找所有匹配选择器的元素。
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
await page.goto('https://www.scrapethissite.com/pages/simple/');
// Extract the first odd row element
const firstOddRow = await page.$('.container .row');
console.log(await firstOddRow.evaluate(node => node.textContent));
// Extract all the odd rows
const allOddRows = await page.$$('.container .row');
for (const oddRow of allOddRows) {
console.log(await oddRow.evaluate(node => node.textContent));
}
await browser.close();
})();如何在 Playwright 中使用 CSS 选择器查找 HTML 元素?
以下是在 Playwright 中实现的方法,其操作方式与 Puppeteer 非常相似:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({
headless: false,
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://www.scrapethissite.com/pages/simple/');
// Extract the first odd row element
const firstOddRow = await page.$('.container .row');
console.log(await firstOddRow.textContent());
// Extract all the odd rows
const allOddRows = await page.$$('.container .row');
for (const oddRow of allOddRows ) {
console.log(await oddRow.textContent());
}
await browser.close();
})();如何在 cheerio 中使用 CSS 选择器查找 HTML 元素?
在 cheerio 中,您需要先获取 HTML 内容(我使用了 request 库来实现),然后将其传递给 cheerio 库:
const request = require('request');
const cheerio = require('cheerio');
const url = 'https://www.scrapethissite.com/pages/simple/';
request(url, (error, response, html) => {
if (!error && response.statusCode === 200) {
const $ = cheerio.load(html);
const firstOddRow = $('.container .row').first();
console.log(firstOddRow.text());
const allOddRows = $('.container .row');
allOddRows.each((i, oddRow) => {
console.log($(oddRow).text());
});
}
});如何在 Puppeteer 中使用 XPath?
在 Puppeteer 中,您可以使用 page.$x() 函数通过 XPath 选择器选择元素:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.scrapethissite.com/pages/forms/');
// Extract the table header elements
const allTableHeaders = await page.$x('//table/tbody/tr[1]//th');
for(let i = 0; i < allTableHeaders.length; i++) {
const header = await page.evaluate(el => el.textContent, allTableHeaders[i]);
console.log(header.trim());
}
await browser.close();
})();
// Output:
// Team Name
// Year
// Wins
// Losses
// OT Losses
// Win %
// Goals For (GF)
// Goals Against (GA)
// + / -如何在 Playwright 中使用 XPath?
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({
headless: false,
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://www.scrapethissite.com/pages/forms/');
// Extract the table header elements
const allTableHeaders = await page.locator('xpath=//table/tbody/tr[1]//th').all();
for (let i = 0; i < allTableHeaders.length; i++) {
const headerText = await allTableHeaders[i].innerText();
console.log(headerText);
}
await browser.close();
})();任何以 // 或 .. 开头的选择器字符串都会被视为 XPath 选择器。例如,Playwright 会将 '//html/body' 转换为 'xpath=//html/body'。
如何在 Puppeteer 中通过文本查找 HTML 元素?
在 Puppeteer 中,通过文本查找元素的最简单方法是使用 XPath 的 text() 函数:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
await page.goto('https://en.wikipedia.org/wiki/Web_scraping');
// Select all the p tags texts that contain the word "prevent"
const pTags = await page.$x('//p[contains(text(), "prevent")]/text()');
for(let i = 0; i < pTags.length; i++) {
const pTag = await page.evaluate(el => el.textContent, pTags[i]);
console.log(pTag,"\n");
}
await browser.close();
})();
//Output:
There are methods that some websites use to prevent web scraping, such as detecting and disallowing bots from crawling (viewing) their pages. In response, there are web scraping systems that rely on using techniques in ... 如何在 Playwright 中通过文本查找 HTML 元素?
若要在 Playwright 中通过文本查找元素,可将 allInnerTexts() 函数与 XPath 结合使用。
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({
headless: false,
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://en.wikipedia.org/wiki/Web_scraping');
// Select all the p tags texts that contain the word "prevent"
const pTags = await page.locator('//p[contains(text(), "prevent")]').allInnerTexts();
for (let i = 0; i < pTags.length; i++) {
console.log(pTags[i], "\n");
}
await browser.close();
})();如何在 cheerio 中通过文本查找 HTML 元素?
const request = require('request');
const cheerio = require('cheerio');
const url = 'https://en.wikipedia.org/wiki/Web_scraping';
request(url, (error, response, html) => {
if (!error && response.statusCode === 200) {
const $ = cheerio.load(html);
// Select all the p tags texts that contain the word "prevent"
const elements = $('p').filter((i, el) => $(el).text().includes('prevent'));
elements.each((i, el) => {
console.log($(el).text());
});
}
});如何在 Puppeteer 中等待选择器?
在 Puppeteer 中,您可以使用 page.waitForSelector() 函数,在脚本继续执行之前等待特定元素出现在页面上。该函数既支持 CSS 选择器,也支持 XPath 选择器:
await page.waitForSelector('.basic-element', { timeout: 10000 });
await page.waitForXPath("//div[@class='basic-element']"), { timeout: 10000 });timeout 参数指定了最大等待时间(单位为毫秒)。
您还可以等待元素达到特定状态:
await page.waitForSelector('.basic-element', { visible: true });// wait until the element becomes visible
如何在 Playwright 中等待选择器?
Playwright 与 Puppeteer 类似。您可以使用 page.waitForSelector() 方法等待特定元素在页面上出现。
await page.waitForSelector('.element-class', { timeout: 10000 });
您还可以等待元素达到特定状态:
await page.waitForSelector('.basic-element', { state: 'visible' });// wait for element to become visible
总结
网页抓取是一个庞大的课题,本文仅涉及皮毛。选择适合您具体用例的工具至关重要。例如,如果您想使用 JavaScript 抓取网站,cheerio 库是一个不错的选择。但是,如果网站需要 JavaScript 完全加载,Puppeteer 或 Playwright 则是更好的选择。网页抓取虽然具有挑战性,但了解这些工具可以为您省去很多麻烦。 希望本文能拓宽您的视野,并祝您在网页抓取的探索中一切顺利。




