JavaScript 与 Python 在网页抓取中的比较

探讨 JavaScript 和 Python 在网页爬虫方面的差异,重点关注易用性、效率和可用的库。
5 min read
Python 与 JavaScript

网页抓取 被广泛应用于从网站收集数据的各种应用中。作为网页抓取过程的一部分,您需要创建脚本,自动从网页收集和处理数据以用于不同的目的,例如市场研究或价格比较。

JavaScript 和 Python 是最广泛使用的两种编程语言。本文根据它们的易用性、效率、可用库和生态系统、社区支持和资源以及动态内容处理来比较这两种语言。文章中提供的代码片段展示了这些比较点。

易用性

JavaScript 是网页开发中最流行的语言,适合于网页抓取,因为它可以使用Puppeteer 和 Cheerio有效地与动态网页交互并进行操作。如果您已经会使用 JavaScript 开发客户端应用,那么您也可以使用 Node.js 在服务器端进行开发,简化开发过程。

以下 JavaScript 代码使用 HTTP 客户端 Axios 获取 https://example.com 页面上的 HTML,然后使用正则表达式查找标题并提取其内容:

import fetch from 'node-fetch';

httpRequest('https://samplewebsite.com')
  .then(rawData => rawData.text())  .then(pageData => {
    const documentHTML = pageData;
    const h1Finder = /<h1>(.*?)<\/h1>/; // Searching for <h1> elements
    const foundH1 = documentHTML.match(h1Finder);
    if (foundH1 && foundH1.length > 1) {
      const extractedHeader = foundH1[1];
      console.log(`Extracted Header: ${extractedHeader}`); // Logging the found header
    } else {
      console.log('Header missing or not found.');
    }
  })
  .catch(fetchError => {
    console.error('Fetching error:', fetchError);
  });

这段代码涉及多个步骤和错误处理,使其显得更加复杂。您还需要使用 catch 处理错误,这增加了 promise 结构的复杂性。

相比之下,Python 以其简单的语法和易用性著称,非常适合没有太多编程经验的人。

以下代码使用 Requests 库加载 https://samplewebsite.com 网页。然后,使用正则表达式查找 HTML 内容中的 title 标签:

import urllib.request
import re

web_address = 'https://samplewebsite.com'
web_request = urllib.request.Request(web_address, headers={'User-Agent': 'Mozilla/5.0'})

# Opening the URL and retrieving the HTML content
with urllib.request.urlopen(web_request) as web_response:
    web_html = web_response.read().decode('utf-8')

h2_regex = re.compile('<h2>(.*?)</h2>', re.IGNORECASE)
h2_search = h2_regex.search(web_html)

if h2_search:
    extracted_title = h2_search.group(1)
    print(f"Extracted H2 Title: {extracted_title}")
else:
    print("H2 title not detected on the webpage.")

这段代码使用 with 语句确保任何异常都由 HTTP 上下文处理,简化了错误处理。

这两种语言都非常适合您的网页抓取项目。如果您有网页开发背景,那么 JavaScript 可能更适合您。而 Python 的简单语法和大量的库更具吸引力,尤其是对于初学者来说,如果您刚开始抓取网页,那么 Python 是一个不错的选择。

效率

比较网页抓取工具的效率时,您需要了解每种语言如何处理问题,例如并发请求的数量和处理数据的能力。工具在这些场景下的性能决定了其数据提取效率,尤其是在从大数据集提取数据或同时从多个来源获取数据时。

您可以使用 Node.js 提高 JavaScript 网页抓取任务的性能。Node.js 使用一种非阻塞 I/O 模型。这种模型允许 JavaScript 同时执行多个抓取任务,因此 JavaScript 代码无需等待每个 I/O 操作完成。在这种情况下,并行处理功能允许您同时从多个来源抓取数据。

这段 JavaScript 代码使用 Axios 并行/并发地向定义在数组 urls 中的不同网页 URL 发送 HTTP GET 请求:

import fetch from 'node-fetch';

const targetURLs = ['https://samplewebsite1.com', 'https://samplewebsite2.org', 'https://samplewebsite3.net'];

targetURLs.forEach(async (endpoint) => {
  try {
    const fetchResponse = await fetch(endpoint);
    const webpageText = await fetchResponse.text();
    console.log(`Received data from ${endpoint}:`, webpageText);
  } catch (fetchIssue) {
    console.error(`Problem retrieving data from ${endpoint}:`, fetchIssue);
  }
});

该代码对多个 URL 执行并发 HTTP GET 请求,并使用 Node.js 异步处理它们的响应。

Python 没有内置的非阻塞 I/O 操作支持,但您可以使用像 Scrapy 这样的框架进行异步处理。Scrapy 框架使用一个叫做 Twisted 的事件驱动网络引擎来处理并发请求,类似于 Node.js 在 JavaScript 中的工作方式。

以下 Python 代码使用 aiohttpasyncio 异步收集数据:

import aiohttp
import asyncio

async def retrieve_web_content(endpoint, client):
    async with client.get(endpoint) as response:
        content = await response.text()
        print(f"Preview from {endpoint}: {content[:100]}")  # Displaying the first 100 characters of the content

async def execute():
    target_sites = ['https://samplewebsite1.com', 'https://samplewebsite2.org', 'https://samplewebsite3.net']
    async with aiohttp.ClientSession() as client_session:
        tasks = [retrieve_web_content(site, client_session) for site in target_sites]
        await asyncio.gather(*tasks)

asyncio.run(execute())

fetch_data() 函数对指定的 URL 进行异步请求。asyncio.gather 同时运行所有这些任务。该代码对多个站点执行并发请求并异步处理响应。

乍一看,JavaScript 似乎表现更好,因为它本质上是非阻塞的,特别是在 I/O 密集型活动中。然而,使用像 Scrapy 这样的框架,Python 可以达到与 JavaScript 相当的性能。无论您喜欢 JavaScript 的内置异步操作还是 Python 的显式异步编程模型,这两种环境都有优化您的网页抓取操作性能的解决方案。

库和生态系统

在构建网页抓取解决方案时,JavaScript 和 Python 都提供了强大的生态系统,拥有各种专为网页抓取设计的库,从处理 HTTP 请求到解析 HTML 和管理浏览器自动化。

JavaScript 生态系统提供了几个非常适合网页抓取任务的库。以下是其中最流行的两个库:

  • Puppeteer: 该库提供了一个高级 API 来管理无头 Chromium 或 Chrome 通过 DevTools 协议。它非常适用于抓取由 JavaScript 生成的动态内容,因为它可以自动化与网站的交互,例如表单提交或按钮点击。您将在下一节动态内容相关的部分中了解更多内容。
  • Cheerio: Cheerio 非常适合快速有效地抓取静态 HTML 页面。Cheerio 解析标记并提供一个 API,可用于遍历和操作生成的数据结构,类似于 jQuery

该代码使用 Axios 从 https://example.com 页面获取 HTML,然后 Cheerio 解析 HTML 内容并提取标题:

const axios = require('axios');
const cheerio = require('cheerio');

axios.get('https://example.com')
  .then(result => {
    const loadedHTML = cheerio.load(result.data);
    const websiteTitle = loadedHTML('title').text();
    console.log(`Webpage Title: ${websiteTitle}`);
  })
  .catch(fetchError => {
    console.error(`Failed to fetch page: ${fetchError}`);
  });

与此同时,Python 有各种抓取库可供使用,具体取决于您的需求,从抓取简单的静态页面到复杂的 web 应用程序。以下是两种最流行的 Python 抓取库:

  • Beautiful Soup: Beautiful Soup 提供快速的HTML 和 XML 解析,因为它易于使用。对于初学者来说,它是一个不错的选择,因为它简单明了,能够轻松管理大多数抓取任务。
  • Scrapy: 这是一个功能强大的框架,能够快速提取大量数据。Scrapy 具有一个异步网络框架,使您能够同时处理多个请求。

以下示例演示了如何使用 Beautiful Soup 抓取数据:

import requests
from bs4 import BeautifulSoup as Soup

# Requesting the web page
page_response = requests.get('https://example.com')
page_soup = Soup(page_response.text, 'html.parser')

# Finding the title of the webpage
page_headline = page_soup.select_one('title').text

# Outputting the webpage title
print(f"Webpage Title: {page_headline}")

在这段代码中,Requests 库加载 https://example.com 网页,Beautiful Soup 解析 HTML 内容,然后 select_one 方法提取页面标题并打印标题。

以下示例演示了如何使用 Scrapy 抓取数据:

import scrapy
from scrapy.crawler import CrawlerProcess

class WebsiteTitleSpider(scrapy.Spider):
    name = 'title_spider'
    allowed_domains = ['example.com']
    start_urls = ['https://example.com']

    def parse(self, response):
        extracted_title = response.xpath('//title/text()').get()
        print(f"Webpage Title Extracted: {extracted_title}")

def main():
    process = CrawlerProcess()
    process.crawl(WebsiteTitleSpider)
    process.start()

if __name__ == '__main__':
    main()

该代码使用 scrapy 定义了一个简单的蜘蛛,从 https://example.com 网页中提取标题。

在库和框架方面,选择 Python 或 JavaScript 主要取决于您的项目需求、个人或团队的能力以及要抓取的内容。对于动态内容以及浏览器自动化,JavaScript 库如 Puppeteer 可能更适用。对于多步网页抓取,您希望进行高级数据处理和分析,或构建具有异步请求的机器学习模型,那么 Python 是更好的选择。

动态内容处理

动态内容使得网页抓取变得更加困难,因为传统的抓取工具无法捕获由 JavaScript 加载的数据。然而,JavaScript 和 Python 都有特定的库,可以像用户一样在浏览器中操作,从而抓取动态生成的内容。在这种情况下,网页完全渲染以执行 JavaScript 生成的内容,然后异步抓取数据。

在 JavaScript 中,Puppeteer 和 Selenium 是两个可以处理动态内容的库:

  • Puppeteer: 该库直接控制 ChromeDriver,非常适合需要与 JavaScript 重度使用的站点交互的任务。
  • Selenium: 另一个用于 JavaScript 执行的强大工具,Selenium WebDriver 可以本地或远程驱动浏览器,实时处理复杂场景。

以下示例演示了如何使用 Puppeteer 抓取动态内容:

const puppeteer = require('puppeteer');

async function extractPageTitle() {
    const navigator = await puppeteer.launch();
    const explorer = await navigator.newPage();
    await explorer.goto('https://example.com');
    const documentTitle = await explorer.evaluate(() => document.title);
    console.log(`Extracted Document Title: ${documentTitle}`);
    await navigator.close();
}

extractPageTitle();

该代码使用 puppeteer 启动一个浏览器实例,访问 https://example.com 页面,检索标题并在控制台中打印。最后,代码执行完成后关闭浏览器。

以下示例演示了如何使用 Selenium 抓取动态内容:

const {Builder, By} = require('selenium-webdriver');

async function scrapeDynamicContent(siteUrl) {
    let browser = await new Builder().forBrowser('chrome').build();
    try {
        await browser.get(siteUrl);
        let targetElement = await browser.findElement(By.id('dynamic-element'));
        let contentOfElement = await targetElement.getText();
        console.log(`Extracted Content: ${contentOfElement}`);
    } finally {
        await browser.quit();
    }
}

scrapeDynamicContent('https://example.com');

这段代码使用 Selenium 网络驱动程序打开 https://example.com 网页,并使用 findElement 方法获取动态内容。最后,代码打印内容并关闭浏览器。

Python 抓取动态内容的方法涉及使用 Selenium 和 pyppeteer(基本上是 Puppeteer 的一个移植,提供类似的功能,如浏览器自动化,以处理 JavaScript 渲染的页面)等类似策略。

以下示例演示了如何使用 Selenium 抓取动态内容:

from selenium import webdriver
from selenium.webdriver.common.by import By

navigator = webdriver.Chrome()
navigator.get('https://example.com')

try:
    activeElement = navigator.find_element(By.ID, 'dynamic-content')
    print(activeElement.text)  # Outputs the text of the dynamic element
finally:
    navigator.quit()  # Ensures the browser closes after the script runs

这段代码使用 Selenium 和 ChromeDriver 打开 https://example.com 网页,并使用 find_element 方法获取动态内容并打印。

以下示例演示了如何使用 pyppeteer 抓取动态内容:

import asyncio
from pyppeteer import launch

async def extractContent():
    client = await launch(headless=True)  # Launch browser
    tab = await client.newPage()  # Open a new tab
    await tab.goto('http://books.toscrape.com/')

    # Wait for the product pods to appear
    await tab.waitForSelector('.product_pod', {'timeout': 10000})  # Wait for a maximum of 10 seconds

    # Extract book titles
    book_titles = await tab.evaluate('''() => {
        const titles = [];
        document.querySelectorAll('.product_pod h3 a').forEach(element => {
            titles.push(element.getAttribute('title'));
        });
        return titles;
    }''')

    print(book_titles)  # Display the extracted book titles

    await client.close()  # Close the browser

asyncio.get_event_loop().run_until_complete(extractContent())

这段代码使用 pyppeteer 从 http://books.toscrape.com/ 页面抓取动态内容。代码首先启动浏览器,打开 http://books.toscrape.com/ 页面,然后使用 querySelectorAll 获取动态内容。最后,代码打印内容并关闭浏览器。

无论使用 JavaScript 还是 Python,这两种语言都允许您抓取动态网页内容。选择哪种语言取决于您的项目的具体要求、您对语言的掌握程度或抓取任务的具体特点。例如,对于大规模数据提取和处理以及构建具有异步请求的机器学习模型,Python 是最佳语言;而 JavaScript 则非常适合从 JavaScript 重度使用的站点抓取动态内容,并使用 Puppeteer 之类的工具进行网页交互自动化。

结论

选择 JavaScript 或 Python 进行网页抓取主要取决于您的项目要求和您最熟悉的语言。如果您是一名网页开发者,或者需要高性能来处理多个操作,那么 JavaScript 是一个极好的选择。如果您重视简洁性和可读性,那么您应该选择 Python。

即使您有合适的工具,网页抓取仍然会遇到挑战,例如 IP 阻止和 CAPTCHA。Bright Data 提供了各种服务,如代理服务、Web 解锁器、IP 轮换、网页抓取 API 和数据集,确保您的抓取活动有效且顺利进行。

要了解更多关于使用 Python 或 JavaScript 进行网页抓取的信息,请查看 Bright Data 的指南 使用 Python 进行网页抓取使用 JavaScript 和 Node.js 进行网页抓取。想跳过手动抓取?试试我们的网页抓取 API 或数据集!