为什么我的数据抓取工具无法看到与浏览器相同的数据?
You've written a script to fetch HTML from a website, but you're not getting the full data. You've tested your selectors in the browser and they should work, right? Not always. Websites that rely on JavaScript to render won't work with a simple GET request. There are libraries like Puppeteer and Selenium that use headless browsers to render JavaScript. They allow you to make the request in the context of a browser and wait for JavaScript to finish executing. This way, you can get the full HTML. You may not always need a headless browser to get the missing data. Search for <script> tags in the HTML. The missing data could be hidden inside <script> tags as JavaScript variables.
如何抓取使用生成式 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>
You can select the second <a> element with:
//div[@class='container']/div/ul[2]/li/aCheerio 比 Puppeteer 更快吗?
是的,Cheerio 通常被认为比 Puppeteer 更快。这是因为 Cheerio 是一个服务器端库,能够直接处理 HTML 内容。而 Puppeteer 是一个浏览器自动化库,通过控制无头浏览器来加载网页并与之交互。Cheerio 的局限性在于它只能处理静态页面,不具备像 Puppeteer 那样与浏览器交互的能力。
XPath 选择器比 CSS 选择器更好吗?
这取决于具体情况。如果你想根据元素的位置来提取数据,XPath 是更好的选择。但是,如果你想根据类名或 ID 等属性来提取数据,CSS 选择器则是更好的选择。
“剧作家”比“木偶师”更好吗?
两者提供的功能大致相同,但。Playwright 支持多种浏览器,包括 Chrome、Firefox 和 Safari。而 Puppeteer 仅支持 Chrome 和 Chromium。
Playwright 在处理多个标签页和窗口方面提供了更好的支持。它还内置了对浏览器上下文、Cookie 和存储的处理功能。Playwright 更适合用于复杂的项目。
如何避免被封IP?
通常,您可以尝试错开请求时间。使用不同的 IP 地址。使用代理。尝试更改浏览器指纹。对大多数人来说,这是一场永无止境的斗争。好消息是,情况不必如此。 您可以使用我们的解决方案——WebScrapingAPI。WebScrapingAPI 提供了一个 API,它将为您处理所有繁重的工作。它能够执行 JavaScript、轮换代理,甚至处理验证码。您再也不必担心 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")
# 获取所有 h2 元素
content = driver.find_element(By.TAG_NAME, "h2")
print(content.text)
# 输出 'From today's featured article'如何使用 BeautifulSoup 根据文本选择 HTML 元素?
With BeautifulSoup, you can use the soup.find method with the text=re.compile("<text>") parameter:
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")
# 获取所有 class 为 vector-body 的元素
span = driver.find_element(By.XPATH, "//span[contains(text(), 'Did')]")
print(span.text)
# 输出 '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")
# 获取所有类名为 vector-body 的元素
elements = driver.find_elements(By.CLASS_NAME, "vector-body")
for element in elements:
print(element.text)
driver.quit()如何在 BeautifulSoup 中使用 XPath?
你需要lxmlPython 库:
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))
# 输出 ['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")
# 该元素不存在,但会等待 10 秒
text = element.text
print(text)
# 关闭浏览器
driver.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")
# 等待页面上出现 ID 为 'content' 的元素
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)
# 关闭浏览器
driver.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 });
超时参数指定了最大等待时间(单位为毫秒)。
你也可以等待某个元素达到特定状态:
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 会是更好的选择。网页抓取虽然具有挑战性,但了解这些工具可以为您省去不少麻烦。 希望本文能拓宽您的视野,并祝您在网页抓取的探索中一切顺利。




