我们使用联盟链接。它们让我们能够维持运营,而您无需承担任何费用。

使用 Python 进行网页抓取:入门所需的一切

本指南为 Python 网页抓取的入门指南,包含分步教程。

使用 Python 缩略图进行网页抓取

Python 可能是机器学习和数据分析领域最流行的语言。但它也是 Web 开发的绝佳选择 数据提取。如果您从事数据工作,那么将这项技能添加到您的投资组合中将非常有意义,而且它还可以带来盈利机会。

本指南将为您提供使用 Python 开始网页抓取所需的一切。它解释了为什么您应该花时间学习 Python,介绍了用于练习网页抓取的库和网站。您还将找到一个逐步教程,用于构建 刮板机 您可以在自己的计算机上复制。让我们开始吧!

Python 中的网页抓取是什么?

网页抓取 指 的过程 从网页下载数据并对其进行结构化以供进一步分析。您可以手动抓取;但是编写一个自动脚本来为您完成这项工作会快得多。

使用这种方法,你不会真正下载人们看到的网页。相反,你提取其底层 HTML 骨架并从那里开始工作。如果你不确定那是什么,请尝试在此页面上单击鼠标右键并选择 检查。现在你应该看到它就像网络爬虫一样:

使用 Python 进行网页抓取
我们正在通过网络抓取工具查看的页面。

Python 的作用是什么?Python 提供了所需的库和框架,可帮助您成功从 Web 上查找、下载和构建数据(换句话说,就是抓取数据)。

为什么选择 Python 进行网页抓取

如果你没有太多的编程经验,或者不懂其他编程语言,你可能会怀疑学习 Python 是否比学习其他语言更划算。以下是你应该考虑学习 Python 的几个原因:

  • 简单的语言。 Python 的语法相对人性化,一眼就能看懂。此外,你不需要编译代码,这使得调试和实验变得简单。
  • 很棒的网页抓取工具。 Python 拥有一些用于数据收集的主要库,例如每月下载量超过 200 亿次的 Requests。
  • 强大的社区。 您在 Stack Overflow 等平台上获取帮助或寻找解决方案时不会遇到问题。
  • 数据分析的热门选择。 Python 与数据分析(Pandas、Matplotlib)和机器学习(Tensorflow、PyTorch)的更广泛生态系统完美结合。

Python 是网页抓取的最佳语言吗?我不会做出如此笼统的陈述。 Node.js 也有一个非常强大的生态系统,你也可以使用 Java、PHP 甚至 卷曲。但如果你没有充分的理由这样做,你不会后悔选择 Python。

Python Web 抓取入门

所以,你决定开始使用 Python 进行抓取。但是你应该从哪里开始呢?首先,重要的是考虑你的抓取工具应该具有哪些功能。

想想目标网站。它是静态的,仅使用文本和图像创建,还是有动态元素,例如弹出窗口、实时内容更新(例如天气预报)?您是要为个人项目抓取一些页面,还是要将其作为经常发生的大规模业务操作?您的答案将决定您需要为 Python 抓取工具添加哪些功能 - 您需要使用哪些库来实现目标。

用于网页抓取的热门 Python 库

有几十种不同的 Python 库可以处理解析、输出、浏览器自动化等任务。它们的组合可以创建强大的网络爬虫,甚至可以从非常受保护的网站提取数据。 

要使用 Python 构建网络抓取工具,您需要一些库来处理 HTTP 请求、自动化无头浏览器、解析数据并保存提取的信息。 

以下是一些流行的 Python 抓取库:

要求处理数据解析浏览器自动化

- 要求
– aiohttp
– httpx
– http.客户端

– 美麗的汤
– lxml
–PyQuery

– 硒
– 剧作家
– Pyppeteer

这些库在易用性、语法、效率和功能方面往往有所不同。如果你是初学者,可以从易于学习的库开始,例如 Requests、Beautiful Soup 和 在构建你的刮刀时。

使用 Python 发送 HTTP 请求

为了从 HTML(静态)网站抓取数据,您需要发送 HTTP 请求来下载目标页面。有几种方法可以做到这一点,但最适合初学者的是使用 Requests 库。

要求

如果这是您的第一个网页抓取项目,我强烈建议您从 HTTP 客户端 Requests 开始。它是一个允许您下载页面的 HTTP 客户端。基本配置只需要几行代码,您可以极大地自定义请求,在转向更复杂的目标时添加标头、cookie 和其他参数。 

要开始使用 Requests,您需要通过运行以下命令来安装它: 点安装请求。然后,创建一个新文件并开始设置你的抓取工具。 

以下是发送 GET 和 POST 请求以及标头的方法:

  • 发送 GET 请求
				
					import requests

# Send a GET request to a URL
response = requests.get('https://example.com')

# Check if the request was successful (status code 200)
if response.status_code == 200:
    # Print the response content
    print(response.text)
else:
    print('Error:', response.status_code)

				
			
  • 发送 POST 请求
				
					import requests

# Data to be sent with the POST request
data = {'key': 'value'}

# Send a POST request to a URL with the data
response = requests.post('https://example.com', data=data)

# Check if the request was successful (status code 200)
if response.status_code == 200:
    # Print the response content
    print(response.text)
else:
    print('Error:', response.status_code)
				
			
  • 发送标头
				
					import requests

# Define custom headers
headers = {'User-Agent': 'MyCustomUserAgent'}

# Send a GET request with custom headers
response = requests.get('https://example.com', headers=headers)

# Check if the request was successful (status code 200)
if response.status_code == 200:
    # Print the response content
    print(response.text)
else:
    print('Error:', response.status_code)
				
			

Python 的 Requests 并不是唯一用于网页抓取的 HTTP 客户端。还有其他替代方案可供您尝试 特别是如果您正在寻求更好的性能或异步功能。

我们编制了一份最佳 Python HTTP 客户端列表供您尝试。

使用 aiohttp 发送 Python 异步请求

Requests 通常很容易掌握,但不幸的是,它只能处理同步请求。这意味着您的抓取工具必须等待一个任务完成后才能开始另一个任务。如果您计划进行大量抓取,那么您将达到这样的程度:同步工具(如 Requests)开始花费太长时间。

异步网页抓取是一种无需等待响应即可发送多个请求的技术。Python 的 aiohttp 库就是为此目的而设计的。 

该工具建立在 Python 内置异步 I/O(输入/输出)框架 asyncio 之上。它使用 异步/等待 语法来管理多个请求而不阻塞主程序的执行。

如果您需要为网络抓取工具设置自定义 API 或端点,aiohttp 允许您构建用于管理异步连接的网络应用程序和 API。 

以下是使用 aiohttp 进行网页抓取的示例:

				
					import aiohttp
import asyncio

async def fetch_data(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    urls = [
        'https://example.com/1',
        'https://example.com/2',
        'https://example.com/3',
        # Add more URLs as needed
    ]

    tasks = [fetch_data(url) for url in urls]
    results = await asyncio.gather(*tasks)
        
    for result in results:
        print(result)

if __name__ == "__main__":
    asyncio.run(main())

				
			

如果您想练习发送异步请求,我们准备了一个包含真实示例的详尽教程。您将学习如何构建一个遍历多个页面并抓取必要信息的脚本。 

本教程将介绍如何使用 aiohttp 发送异步请求并并行抓取多个页面的网页。

使用 Python 进行数据解析

从目标网站下载数据后,这些数据仍然没什么用处——由于没有结构,因此很难阅读和理解。要从抓取的数据中获取有价值的见解,您需要对其进行解析。

解析是根据给定的参数清理和构造数据并从中提取相关信息的过程。当然,您可以手动完成此操作,但这需要大量资源。您可以使用 Python 的解析库,而不必手动处理大量数据。  

Python 有各种用于处理 HTML 的库,例如 BeautifulSoup 和 lxml。这些库允许您浏览 HTML 文档并提取目标数据。但是,它们不能作为独立工具运行,因此您还需要使用 HTTP 客户端来构建抓取工具。 

美丽的汤

Beautiful Soup 是一个数据解析库,它从您下载的 HTML 代码中提取数据并将其转换为结构化格式。它的语法简单易懂,工具本身功能强大、文档齐全,对初学者来说也很方便。

这个库非常强大。它带有三个内置解析器 - lxml、html.parser、HTML5lib - 因此您可以充分利用每个解析器。它占用的资源也很少,因此比其他工具更快。此外,Beautiful Soup 是少数几个可以处理损坏页面的库之一。

要开始使用 Beautiful Soup,您需要通过运行以下命令来安装它: pip 安装 beautifulsoup

下面是一个如何使用 Beautiful Soup 进行抓取的示例:

				
					from bs4 import BeautifulSoup

html_data = """
<html>
    <body>
        <h1>Welcome to my website</h1>
        <p>This is a paragraph.</p>
        <a href="https://example.com">Link</a>
    </body>
</html>
"""

soup = BeautifulSoup(html_data, 'html.parser')

print("Title:", soup.h1.text)
print("Paragraph:", soup.p.text)
print("Link URL:", soup.a['href'])

				
			

要了解有关 Beautiful Soup 网页抓取的更多信息,您可以直接进入我们的分步教程。您将通过一个真实示例了解如何构建一个简单的抓取工具。该指南还将教您如何从单个静态页面中提取数据并将其添加到 CSV 文件中以供进一步分析。 

使用 Beautiful Soup 进行网页抓取的分步指南。

xml文件

lxml 是一个功能强大的解析库。该工具包装了两个 C 库 - libxml2 和 libxalt - 使 lxml 可扩展。它包括它们的功能,例如速度和本机 Python API 的简单性。 

lxml 的主要优点是它不占用大量内存,因此您可以快速解析大量数据。该库还支持三种模式语言,并可以完全实现用于识别 XML 文档中元素的 XPath。 

以下是使用 lxml 解析的示例:

				
					from lxml import etree

html_data = """
<html>
    <body>
        <h1>Text</h1>
        <p>This is a paragraph.</p>
        <a href="https://example.com">Link</a>
    </body>
</html>
"""

# Parse the HTML 
root = etree.HTML(html_data)

# Extract information
title = root.find('.//h1').text
paragraph = root.find('.//p').text
link_url = root.find('.//a').get('href')

# Print the results
print("Title:", title)
print("Paragraph:", paragraph)
print("Link URL:", link_url)

				
			

要了解有关网页静态页面抓取的更多信息,请查看我们的 lxml 和 Requests 教程。您将学习如何获取 HTML 数据、解析数据、添加浏览器指纹以及从热门电影平台 IMDb 提取数据。

使用 Beautiful Soup 进行网页抓取的分步指南。

Beautiful Soup 与 xlml 的区别

那么,为什么你会选择 lxml 而不是 Beautiful Soup 或反之亦然?有几个关键的区别可以决定哪个库更适合您的用例。

首先,lxml 可以 更难理解 对于初学者来说。虽然它不是很复杂,但它需要对 HTML 树结构有更深入的了解,语法更复杂,并且对损坏的 HTML 的容忍度较低——Beautiful Soup 处理得更好。

其次,速度也很重要。lxml 比 Beautiful Soup 更快,占用的资源更少,更适合小规模的解析项目。Beautiful Soup 功能强大且快速,但由于需要额外的数据处理,解析时间会稍长一些。此外,Beautiful Soup 可能难以完成重复的解析任务。

最后,由于原生支持 XPath,lxml 在处理 XML 文档时是更好的选择。XPath 有助于更有效地定位元素和处理高级查询。也就是说,如果您打算处理 HTML 文档,Beautiful Soup 可能更好。

BeautifulSoup 和 lxml 库之间的区别
BeautifulSoup 和 lxml 库之间的区别

使用 Selenium 构建 Python 无头浏览器

无头浏览器 当网站通过 JavaScript 等客户端脚本语言动态生成内容时,动态网页就变得必不可少。与可以直接检索 HTML 内容的静态网页不同,动态网页需要先对其进行渲染。

Selenium 是编程控制无头浏览器的最古老的工具之一。尽管 Selenium 的主要用途是浏览器自动化,但它仍然是基于 JavaScript 的网站网页抓取的热门选择。它可以控制大多数流行的网页浏览器,并支持多种编程语言。

该库还包含用于隐藏数字指纹的软件包。正确配置后,它可以自动登录或通过 reCAPTCHA,这通常是抓取热门网站的主要障碍。

以下是使用 Selenium 进行网页抓取的示例:

				
					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

# Set up Selenium WebDriver (make sure to download the appropriate driver for your browser)
driver = webdriver.Chrome('/path/to/chromedriver')

# Navigate to the webpage
driver.get('https://example.com')

try:
    # Wait for the element to be loaded (for demonstration purposes, let's wait for the page title)
    WebDriverWait(driver, 10).until(EC.title_contains("Example"))

    # Once loaded, find the element(s) you want to scrape
    elements = driver.find_elements(By.CSS_SELECTOR, 'p')  # Example: find all <p> elements

    # Extract data from the elements
    for element in elements:
        print(element.text)

finally:
    # Close the WebDriver session
    driver.quit()

				
			

如果您想了解有关使用 Selenium 进行网页抓取的更多信息,我们为初学者准备了一个指南。在本教程中,您将学习如何处理 JavaScript 生成的内容、抓取多个页面、处理延迟渲染以及将结果写入 CSV 文件。

使用 Selenium 进行网页抓取的分步指南。

Selenium 是一个不错的入门库,因为它很流行,但它也有一些缺点,比如速度和设置难度。如果这对你来说是个问题,Python 还有其他可以处理基于 JavaScript 的网站的框架。 

哪一个更适合网页抓取?

哪种工具更适合您的项目需求?

其他 Python Web 抓取库

Python 网页抓取库不缺。您选择的工具取决于您的项目参数,包括目标网站的类型(静态或动态)、要抓取的数据量以及其他方面。

熟悉主要的 Python 网络抓取库并找到最适合您的抓取项目的库。

使用 Python 进行网页抓取的另一种方法是使用 cURL 命令行工具。它比 Python 库具有多项优势,例如 HTTP 客户端请求。例如,它非常快,您可以通过多个连接发送许多请求。

本教程将向您展示使用 cURL 和 Python 来收集数据的基础知识。

使用 Python 进行社交媒体网页抓取

网页抓取社交媒体 并不容易。社交平台可能是对自动数据收集最为严格的平台,并且经常寻找关闭网络抓取公司的方法。虽然收集公开信息是合法的,但并非没有障碍。

许多企业和个人营销人员使用社交媒体抓取来执行情绪分析、分析市场趋势、监控在线品牌或寻找有影响力的人。

如果您想尝试抓取社交媒体的技能,我们准备了涵盖最流行平台的 Python 指南。请记住,所有抓取工具都是为公开可用的数据构建的。此外,社交媒体平台经常会进行更新,这可能会影响您的抓取工具,因此您可能需要进行一些调整。 

有关如何使用 Python 抓取 Reddit 数据的分步教程。

有关如何使用 Python 抓取 Facebook 数据的分步示例。

有关如何使用 Python 抓取 Instagram 数据的分步指南。

Python 网页抓取技巧

设计一个网页抓取项目

如果您没有考虑业务用例,那么很难找到有价值的想法。我建议使用虚拟网站进行练习。它们是专门为抓取而设计的,因此您可以在安全的环境中尝试各种技术。您可以在我们的列表中找到几个这样的网站 练习网页抓取技能的网站.

如果你更愿意抓取真正的目标,那么从简单的事情开始是个好主意。像谷歌和亚马逊这样的热门网站提供了有价值的信息,但你会遇到严重的 网页抓取挑战 开始扩展时,您可能会遇到像 CAPTCHA 这样的问题。如果没有经验,这些问题可能很难解决。

无论如何,你应该遵循一些指导原则来避免麻烦。尽量不要让服务器超载。并且要非常小心地抓取登录背后的数据——这已经导致多家公司被起诉。你可以在我们的文章中找到更多建议 网络抓取最佳实践.

最后,你的项目至少应该有这些基本参数:目标网站、你想要从中抓取的 URL 列表以及你感兴趣的数据点。如果你对抓取什么内容缺乏想法,我们准备了一个实用的 Python 项目列表供你尝试。

适合初学者和高级用户的想法。

使用代理

随着项目范围的扩大,您应该考虑使用代理。代理通过为您提供更多 IP 地址,为您提供了避免被阻止的最简单方法。首先,您可以考虑 免费代理名单 (因为它是免费的!),但我建议投资 付费轮换代理.

代理服务器会通过自身路由流量,同时更改您的真实位置并为您提供不同的 IP 地址。当您在执行自动化操作时需要隐藏身份时,这一点尤为重要。 

如果你打算爬取像亚马逊这样的重要目标,那么你应该选择 住宅代理。您将获得一个来自 Wi-Fi 上难以检测到的真实设备的 IP 地址池。 

对于未受保护的网站,您可以通过选择来节省资金 数据中心代理。它们比家用的同类速度快得多,但相对容易被发现。 

使用抓取工具设置代理并不是那么困难,尤其是当大多数代理服务提供商都包含如何使用最流行的语言和工具进行设置的说明时。 

这是有关如何使用 Python 设置和验证 Selenium 代理的分步指南。

构建你的第一个 Python Web 爬虫

现在您已经熟悉了多个 Python 库和一些语法,让我们一起构建一个简单的 Python 抓取工具。

快速 Python 网页抓取教程

假设您经营一家在线图书公司。您的主要竞争对手在 books.toscrape.com 上销售图书,您想了解有关其目录的更多信息。

书籍-toscrape-main
books.toscrape.com 主页

总共有 1,000 本书,每页 20 本书。手动复制所有 50 页会很疯狂,所以我们将构建一个简单的网络抓取工具来为我们完成这项工作。它将收集竞争对手书籍的标题、价格、评级和可用性,并将这些信息写入 CSV 文件。

硬件需求

我们需要的工具有:
  • Python的3(如果你的电脑上还没有) 皮普 安装必要的库。
  • 美丽汤。您可以通过运行来添加它 pip install beautifulsoup4 在您的操作系统终端中。
  • 要求。您可以通过运行来添加它 pip install requests.

导入库

我们需要做的第一件事是导入 要求 和 美丽的汤:

				
					from bs4 import BeautifulSoup
import requests
				
			

我们还需要另外一个库来将抓取的数据添加到 CSV 文件中:

				
					import CSV

				
			

下载页面

现在,是时候下载页面了。 要求 库使一切变得简单——我们只需要编写两行代码:

				
					url = "http://books.toscrape.com/"
r = requests.get(url)
				
			
有些网站可能不会让你轻易退出——你可能需要发送不同的用户代理并跳过其他环节。(在 OxyCon 会议 被称为 如何抓取未来的网络 以非常有趣的方式呈现它们。)但现在让我们保持简单。

提取相关数据点

现在,是时候使用 Beautiful Soup 提取我们需要的数据了。我们首先为抓取的页面创建一个 Beautiful Soup 对象:

				
					soup = BeautifulSoup(r.content , "html.parser")

				
			

然后,我们需要确定特定数据点的位置。我们需要四个元素:书名、价格、评分和可用性。检查页面后,我们可以看到它们都属于一个名为 product_pod:

bookstoscrape 检查视图

我们可以尝试提取整个类:

				
					element = soup.find_all(class_="product_pod") print(element)

				
			
但这会返回太多(并且太混乱!)的数据:
productpod 印刷
因此,我们需要更具体一些。总共有 20 本书;让我们为每本书的相关元素创建一个循环 product_pod:
				
					for element in soup.find_all(class_='product_pod'):

				
			

现在,让我们提取页面标题。它嵌套在 H3,在 <a> 标签。我们可以简单地使用 H3,并通过指定我们想要的字符串来删除不必要的数据(例如 URL):

				
					book_title = element.h3.string 

				
			

书价属于以下类别: price_color我们将提取不带磅号的符号:

				
					book_price = element.find(class_='price_color').string.replace('£','')

				
			

图书评级如下 p 标签。它们更难获取,因为评级本身就包含在名称中,而名称包含两个单词(而我们只需要一个!)。可以通过将类提取为列表来解决这个问题:

				
					book_rating = element.p['class'][1]

				
			

最后,还有库存情况。它属于一个名为 instock。我们将提取文本并删除不必要的元素(主要是空格):

				
					 #book_stock = element.find(class_="instock").get_text().strip()

				
			

以下是完整循环:

				
					for element in soup.find_all(class_='product_pod'):     
    book_title = element.h3.string
    #getting the price and ridding ourselves of the pound sign     
    book_price = element.find(class_='price_color').string.replace('£','')     
    #getting the rating     
    #finding element class but it has two: star-rating and 'num' 
    #e.g. 'One' so we're only getting the second one     
    book_rating = element.p['class'][1]     
    #finding availability     
    book_stock = element.find(class_="instock").get_text().strip()
    #we can also use:     
    #book_stock = element.select_one(".instock").get_text().strip()     
    
    #print out to double check     
    print(book_title)     
    print(book_url)     
    print(book_price)     
    print(book_rating)     
    print(book_stock)
				
			
不要害怕摆弄代码。例如,尝试删除 [1] 来自 book_rating 对象。或者,删除 .strip 看看会发生什么。Beautiful Soup 有很多功能,因此很少只有一种合适的方法来提取内容。 Beautiful Soup 的文档 你的朋友。

将输出导出为 CSV

此时,我们的脚本返回了我们想要的所有数据点,但它们不太容易使用。让我们将输出导出到 CSV 文件。

首先,我们创建一个空列表对象:

				
					books = []

				
			

然后,我们将数据点附加到列表中:

				
					books.append({     
    'title': book_title,     
    'price': book_price,
    'rating': book_rating,     
    'stock': book_stock,
    'url': book_url
    }     
    )
				
			

最后,我们将数据写入 CSV 文件:

				
					proxies = {
    'http': 'http://user:password@host:PORT',
    'https': 'http://user:password@host:PORT',
}

response = requests.get('URL', proxies = proxies)
				
			

最后,我们将数据写入 CSV 文件:

				
					with open("books_output.csv", "a") as f:     
    for book in books:         
        f.write(f"{book['title']},{book['price']},{book['rating']},{book['stock']},{book['url']}\n")
				
			

这给了我们一个格式正确的 CSV 文件(没有 URL – 如何提取它就看你自己了!):

bookstoscrape csv 文件截图

完整脚本如下:

				
					from bs4 import BeautifulSoup import requests import CSV url = "http://books.toscrape.com/"
r = requests.get(url) soup = BeautifulSoup(r.content , "html.parser") #books will be a list of dicts
books = []

for element in soup.find_all(class_='product_pod'):     
    book_title = element.h3.string
    #getting the price and ridding ourselves of the pound sign     
    book_price = element.find(class_='price_color').string.replace('£','')     
    #getting the rating     
    #finding element class but it has two: star-rating and 'num'      
    #e.g. 'One' so we're only getting the second one     
    book_rating = element.p['class'][1]     
    #finding availability     
    book_stock = element.find(class_="instock").get_text().strip()
    #we can also use:     
    #book_stock = element.select_one(".instock").get_text().strip()    

    books.append({     
    'title': book_title,     
    'price': book_price,     
    'rating': book_rating,     
    'stock': book_stock,     
    'url': book_url
    }     
    )

#write it to a csv file with open("books_output.csv", "a") as f:
#not writing in a header row in this case
#if using "a" then you can open a file if it exists and append to it
#can also use "w", then it would overwrite a file if it exists
    for book in books:
        f.write(f"{book['title']},{book['price']},{book['rating']},{book['stock']},{book['url']}\n")
				
			

下一步

等一下,那只有一页。我们不是应该抓取全部 50 页吗?

没错。但此时你应该开始掌握窍门了。那么,为什么不自己尝试抓取其他页面呢?你可以使用以下教程作为指导:

分步教程展示如何获取多个页面的 URL 并抓取它们。

获取个别书籍的信息也很有用。为什么不尝试抓取它们呢?这需要从表中提取数据;这里有另一个教程可以帮助您。您可以在我们的 知识库.

逐步指南展示如何从表中抓取数据。

Chris Becker 的照片
克里斯·贝克尔
代理审阅者和测试者。