in

如何使用 PycURL 进行网页抓取?

如何使用 PycURL 进行网页抓取

这是一个关于如何使用 Python cURL 的指南,使用的是 PycURL 库。你将学习有关 cURL 的所有内容,以及如何在 Python 中使用它。然后,你会看到从头到尾使用 PycURL 抓取网站的示例,包括 GET 和 POST 请求,以及读取 JSON 数据。


什么是 cURL?

简而言之,cURL 是一个用于连接服务器的命令行工具。你可以使用它通过 HTTP 和许多其他协议从服务器获取或发送数据。因此,cURL 是一个用于通用服务器连接的可靠工具,从网页抓取到加载电子邮件都可以使用它。

在网页抓取方面,cURL 是抓取静态网站、XHR 内容和从 API 加载数据的强大工具。

静态网站是指将整个内容呈现为单个 HTML 文件的网站。例如,当你请求 Wikipedia 页面时,它会将整个 HTML 代码提供给你。因此,你不需要处理其中的任何 JS 代码,只需加载这个 HTML 代码并抓取你想要的数据即可。

对于抓取 XHR 内容,这是现代网站的一个不错选择。例如,如果你抓取像 Reddit 这样的网站的 HTML 代码,可能不会有太多数据。它的大部分内容是在初始加载后通过 JS 加载的。

如果你愿意,可以使用浏览器检查器在网络选项卡中查看 XHR 请求。

下面是一个例子:

pycurl 1.png

你可以使用 cURL 模拟这个 GET 请求并获取热门搜索。虽然找到哪个请求加载哪个模板部分可能比较困难,但之后运行 cURL 命令并抓取这些数据就相当容易了。

Python 中的 cURL 等价物是什么?
Python 没有原生的 cURL 命令。不过,你可以使用一个库来帮助你连接服务器并加载数据。

PycURL 是一个库,它允许你通过 Python 命令运行 cURL,作为 libcurl 的接口。还有其他用于连接服务器的库,比如 wget、urllib、httpx 甚至 request 模块。

PycURL 有自己的语法,这与在命令行中使用的纯 cURL 语法不同。因此,你需要将你的 cURL 调用转换为 Python 命令。如果你只是想将原始的 cURL 命令复制到 Python 中,可以使用 subprocess.call 或其他库。


如何使用 PycURL

你需要安装并导入 PycURL 才能在项目中使用它。具体代码中,你需要两个变量:

  • 连接变量 – 这个变量保存 PycURL 命令、选项并运行连接
  • 输出变量 – 这个变量保存你作为响应接收到的内容,因此连接变量写入输出变量,你在项目中使用输出变量

如何安装 PycURL

首先,确保你已经安装了 Python。你可以从 Python 下载页面下载最新版本。最新版本包含了 pip 和 OpenSSL,所以你不需要单独安装它们。

安装 PycURL 的正确命令取决于你在服务器上安装 Python 的方式。它可能像下面这样简单:

pip install pycurl

但可能你需要一些不同的操作。例如,如果你在 macOS 上安装了 Python,你会有 macOS 自带的默认 Python 版本(如 2.7)。因此,如果你在终端中直接运行“python”,你运行的是不包含 pip 的旧版本。

在这种情况下,你需要使用其别名运行新版本,例如 python3 或 python3.11(两者都会调用 python3.11)。

如果你想在最新版本上安装 PycURL,可以运行以下命令:

python3.11 -m pip install pycurl

你也可以只使用主版本号,比如:

python3 -m pip install pycurl

或者用版本号调用pip,如下所示:

pip3 install pycurl

如何运行 PycURL

一旦你安装了 Python 和 PycURL,就可以开始编写一些代码了。你可以使用任何你喜欢的文本编辑器,然后使用命令行来解释这些代码,如下所示:

“`bash
python main.py
“`

别忘了使用正确的 Python 别名,特别是当你安装了多个 Python 版本时(比如在 macOS 上)。例如,在我的 Mac 上,我需要使用:

python3 main.py

或者使用完整的版本名称:

python3.11 main.py

这些命令会告诉终端执行 main.py 文件的 Python 编译器。因此,请确保你已经使用终端导航到正确的文件夹,否则它会尝试在一个不存在的文件上执行此命令。

现在让我们创建 main.py 文件,并使用以下代码:

import pycurl
from io import BytesIO

#set up variables
body = BytesIO()
connection = pycurl.Curl()

#curl url
connection.setopt(connection.URL, 'https://ipv4.icanhazip.com/')

#write data to the output variable
connection.setopt(connection.WRITEDATA, body)

#run the command
connection.perform()

#end the session
connection.close()

#extract the response body from the output variable
get_body = body.getvalue()

#decode the utf8 result and display the source code
print('cURL request Body:\n%s' % get_body.decode('utf8'))

这是你会得到的结果:

pycurl 2.png

这段代码做了几件事:

  1. 导入执行 PycURL 和数据缓冲的库——这些行是必需的
  2. 创建变量来保存数据缓冲和 cURL 连接
  3. 在连接变量中设置 URL
  4. 运行连接
  5. 关闭 PycURL
  6. 提取变量内容并打印出来

如何在 Python 中使用带有头信息的 cURL

你可能已经注意到,运行 cURL 命令的关键是将它们发送到连接变量。因此,你可以使用该变量来设置头信息或自定义 cURL 选项。

自定义头信息非常重要,因为你需要代理来抓取网站而不被封锁。

尽管网页抓取是合法的,网站所有者通常会尝试阻止它。他们通常通过检查连接头信息和 IP 地址来实现这一点。首先,他们检查头信息以确保连接请求看起来像是来自真实浏览器的合法请求。然后,他们检查 IP 地址以查看该用户是否加载了太多页面或加载页面过快。

因此,你需要使用住宅代理服务,你可以在每次请求时更改你的 IP 地址。这样网站所有者就无法检测到你加载的页面是发送到同一个地方的。在他们看来,这些是来自世界各地不同访客的不同请求。

我们以IPRoyal为例,你注册后将在客户端区域看到这些信息:

IPRoyal residential proxies dashboard

你可以在代码中添加 HTTP 代理 URL、端口、用户名和密码,如下所示:

import pycurl
from io import BytesIO

#set up variables
body = BytesIO()
connection = pycurl.Curl()
host = "geo.iproyal.com"
port = "12321"
username = "username"
password = "password"

# set headers
connection.setopt(pycurl.USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0) Gecko/20100101 Firefox/8.0')

# set proxy
connection.setopt(pycurl.PROXY, f"http://{host}:{port}")

# proxy auth
connection.setopt(pycurl.PROXYUSERPWD, f"{username}:{password}")

#curl url
connection.setopt(connection.URL, 'https://ipv4.icanhazip.com/')

#write data to the output variable
connection.setopt(connection.WRITEDATA, body)

#run the command
connection.perform()

#end the session
connection.close()

#extract the response body from the output variable
get_body = body.getvalue()

#decode the utf8 result and display the source code
print('cURL request Body:\n%s' % get_body.decode('utf8'))

这是你会看到的结果:

pycurl 3.png

注意到这与原始响应不同,显示代理连接起作用了。

在这种情况下,代码非常相似,但有一些新的元素:

  • 更多变量来轻松保存代理数据(主机、端口、用户名、密码)
  • `connection.setopt(pycurl.USERAGENT, ‘Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0) Gecko/20100101 Firefox/8.0')` – 这是一个自定义用户代理,否则 PycURL 会将自己标识为 PycURL,这对网站所有者来说很容易封锁
  • `connection.setopt(pycurl.PROXY, f”http://{host}:{port}”)` – 再次使用 setopt 设置代理 URL 和端口
  • `connection.setopt(pycurl.PROXYUSERPWD, f”{username}:{password}”)` – 最后是用户名和密码

你可以使用相同的逻辑添加任何你想使用的自定义头信息,只要它们是通过 setopt 添加的。


PycURL 示例

现在让我们了解 PycURL 在你的网页抓取项目中如何有用。特别是,让我们探索不同的连接类型以及一些使用它们的示例。

PycURL GET 示例

GET 连接是最简单的浏览器连接形式。这与在 URL 栏中输入一个地址是一样的。你可以使用 GET 请求来抓取简单的网站,比如维基百科。

你可以使用一个库,如 Python 的 HTMLParser

以下是一个简单的示例,从连接请求开始:

import pycurl
from io import BytesIO

#curl url
connection.setopt(connection.URL, 'https://en.wikipedia.org/wiki/Yoda')

#write data to the output variable
connection.setopt(connection.WRITEDATA, body)

#run the command
connection.perform()

#end the session
connection.close()

#extract the response body from the output variable
get_body = body.getvalue()

#start parsing the contents
from html.parser import HTMLParser
class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
#if it’s a meta tag
        if (tag == "meta") :
#if the meta property is og:title
            if ( attrs[0][1] == 'og:title') :
#then display the meta contents
                print("Found a title:", attrs[1][1])

parser = MyHTMLParser()

这是结果

pycurl 4.png

在这个示例中,我们连接到维基百科,并将响应保存到一个变量中。然后我们解析这个变量。

文档中的 meta 标签都有两个属性,形式如下:

  • [“property”, “value”]
  • [“content”, “value”]

这是因为它们的 HTML 代码类似于这样:

<meta property=”propertyname” content=”propertyvalue” />

因此,如果你想检查一个标签的属性,可以通过 `attrs[0][1]` 访问,这就是我们用来检查它是否是 “og:title” 的方法。然后,要检查该属性的内容,你可以使用 `attrs[1][1]`,这就是我们用来显示内容的方法。

这只是一个简单的示例,但你可以用这种方法抓取整个页面,将不同的标签保存到列表中,然后再进行处理。

PycURL POST 示例

有时候你可能需要向页面发送 POST 请求。例如,你可能需要填写一个产品请求表单,或者发送一个搜索表单。在这种情况下,你可以使用以下语法:

import pycurl
from io import BytesIO
from urllib.parse import urlencode

#curl url
connection.setopt(connection.URL, 'https://httpbin.org/post')

#post fields
fields = {'search': 'test query'}

#adding the fields to the request
connection.setopt(connection.POSTFIELDS, urlencode(fields))

#write data to the output variable
connection.setopt(connection.WRITEDATA, body)

#run the command
connection.perform()

#end the session
connection.close()

#extract the response body from the output variable
get_body = body.getvalue()

#decode the utf8 result and display the source code
print('cURL request Body:\n%s' % get_body.decode('utf8'))

结果如下:

pycurl 5.png

在这种情况下,你需要加载 `urllib` 库来编码 POST 变量。然后,你只需定义这些变量并将它们添加到你的请求中。

PycURL XHR 或 API 连接

如果你想使用 PycURL 加载 XHR 资源或连接到 API,你可以使用 GET 或 POST 请求。具体使用哪种请求取决于你要做什么。例如,一些 API 端点需要你发送一些数据进行处理。

让我们加载本教程开头提到的 Reddit 热门项目。注意,这些热门项目是通过 GET 请求加载的,因此你不需要发送任何 POST 字段:

pycurl 6.png

接下来,右键点击该项目并复制 URL。它看起来像这样:

https://www.reddit.com/api/trending_searches_v1.json?withAds=1&subplacement=tile&raw_json=1&gilding_detail=1

然后,您只需要用cURL加载这个URL并处理JSON数据。

这是完成它的代码:

import pycurl
from io import BytesIO
import json

#curl url
connection.setopt(connection.URL, 'https://www.reddit.com/api/trending_searches_v1.json?withAds=1&subplacement=tile&raw_json=1&gilding_detail=1')

#write data to the output variable
connection.setopt(connection.WRITEDATA, body)

#run the command
connection.perform()

#end the session
connection.close()

#extract the response body from the output variable
get_body = body.getvalue()

#save json data in a variable
json_data = json.loads(get_body.decode('utf8'))

#print the variable:
print(json_data)

结果如下:

pycurl 7.png


常见问题

No module named ‘pycurl'

这意味着你的 Python 编译器中没有安装 pycurl。如果还没有安装,请运行 `pip install pycurl`。如果已经安装,请仔细检查是否有多个 Python 版本,你可能使用了错误的版本来运行脚本。

如果这些方法都不奏效,那么是时候重新安装 pycurl 并再次检查了。

Pip install pycurl not working

这种情况通常发生在你没有安装 pip 或者缺少安装 pycurl 所需的某些库(例如 openssl)。

仔细检查你是否运行了正确的 pip 命令(在适用时使用 pip3)。如果这仍然不起作用,你可能需要删除当前的 Python 版本,包括 pip,然后重新安装。

ImportError: pycurl: libcurl link-time version is older than compile-time version

当 PycURL 使用的 cURL 版本较旧时,会发生此错误。这通常是因为你安装了多个 cURL 版本,而旧版本是默认版本。

在这种情况下,移除 PycURL,安装最新的 cURL 版本,添加环境变量,使用如下命令:

export LDFLAGS="-L$HOME/curl-7.86.0/lib -L/opt/homebrew/opt/openssl@3/lib"

export CPPFLAGS="-I$HOME/curl-7.86.0/include -I/opt/homebrew/opt/openssl@3/include"

export PATH="$(HOME)/curl-7.86.0/bin:$PATH"

然后运行命令:

pip install --no-cache-dir --compile
--install-option="--with-openssl" pycurl

这应该是重新安装 PycURL 并使用正确的 cURL 版本的万能方法。


结    论

今天我们学习了如何使用 PycURL 在 Python 中运行 cURL。到今天结束时,你应该能够对各种类型的网站(无论是静态的还是动态的)执行请求并抓取数据。

Written by 河小马

河小马是一位杰出的数字营销行业领袖,广告中国论坛的重要成员,其专业技能涵盖了PPC广告、域名停放、网站开发、联盟营销以及跨境电商咨询等多个领域。作为一位资深程序开发者,他不仅具备强大的技术能力,而且在出海网络营销方面拥有超过13年的经验。