揭秘PC端爬虫工程师必备的网络请求技巧,让你轻松采集所需数据

网络请求是爬虫工程师采集数据的重要手段之一。在PC端爬虫中,网络请求通常使用HTTP协议进行通信,通过发送HTTP请求获取目标网站的数据。

爬虫工程师需要掌握HTTP协议的基本知识,包括HTTP请求和响应的格式、常见的HTTP请求方法(如GET、POST等)、HTTP请求头和响应头的常见字段等。

在进行网络请求时,爬虫工程师通常使用HTTP客户端库,如Python中的requests库、Java中的HttpClient等。这些库封装了HTTP协议的细节,提供了简单易用的API,方便爬虫工程师进行网络请求。

爬虫工程师还需要了解一些反爬虫技术,如User-Agent伪装、IP代理等,以应对目标网站的反爬虫策略。

一丶requests

1.requests源码解析

对于爬虫工程师来说,网络请求是常用的数据采集方式之一。而Python的requests库,作为一个高效且易用的HTTP请求库,被爬虫工程师广泛使用。在深入学习requests库前,建议先了解下其中的源码实现。

requests库是基于urllib3库封装的,所以在使用requests库时需要先安装对应的依赖库urllib3。

接下来,我们通过分析requests库的源代码,来了解其中的一些实现细节。

首先是发送请求的实现,即requests库中的Request类。Request类用于封装发送请求的参数,并通过一个Session对象发送请求并返回响应。以下是Request类的核心代码:

class Request:

    @staticmethod
    def send(session, method, url, **kwargs):
        # ...
        resp = session.request(method=method, url=url, **kwargs)
        return resp

我们可以看到,Request类中的send方法调用了Session对象的request方法,这个方法是整个库中负责发送请求和返回响应的核心方法。以下是Session类中request方法的核心代码:

class Session:

    def request(self, method, url, params=None, data=None, headers=None, cookies=None, files=None, auth=None,
                timeout=None, allow_redirects=True, proxies=None, hooks=None, stream=None, verify=None, cert=None,
                json=None):            
        # ...
        return self.send(prep, **send_kwargs)

我们可以看到,Session对象的request方法的参数和关键字参数与HTTP请求的相关部分一一对应,其中最重要的是prep参数(即经过预处理的Request对象),它包含了请求的相关信息,如请求方法,请求头,请求体等。Session对象的request方法最终调用了self.send方法,即发送HTTP请求并返回响应。

requests库实现了带有各种HTTP请求方法的函数接口,如requests.get()requests.post()等,这些接口在内部会自动创建一个Session对象,然后调用Session对象的request方法,从而返回请求响应。

总体来说,requests是一个功能强大的HTTP请求库,它的源代码实现清晰、易于阅读和理解,掌握其中的实现细节可以帮助我们更好的使用这个库。

2.requests常用方法

requests是一个Python第三方库,用于发送HTTP请求。以下是requests常用方法:

  • requests.get(url, params=None, **kwargs):发送GET请求,url为请求的URL地址,params为请求参数,kwargs为其他可选参数。

  • requests.post(url, data=None, json=None, **kwargs):发送POST请求,url为请求的URL地址,data为请求数据,json为请求的JSON数据,**kwargs为其他可选参数。

  • requests.put(url, data=None, **kwargs):发送PUT请求,url为请求的URL地址,data为请求数据,**kwargs为其他可选参数。

  • requests.delete(url, **kwargs):发送DELETE请求,url为请求的URL地址,**kwargs为其他可选参数。

  • requests.head(url, **kwargs):发送HEAD请求,url为请求的URL地址,**kwargs为其他可选参数。

  • requests.options(url, **kwargs):发送OPTIONS请求,url为请求的URL地址,**kwargs为其他可选参数。

  • requests.request(method, url, **kwargs):发送自定义请求,method为请求方法,url为请求的URL地址,**kwargs为其他可选参数。

  • requests.session():创建一个Session对象,用于保持会话状态。

  • requests.get(url, headers=headers):发送GET请求,并设置请求头。

  • requests.get(url, cookies=cookies):发送GET请求,并设置请求的Cookies

  • requests.get(url, proxies=proxies):发送GET请求,并设置代理服务器。

  • requests.get(url, timeout=timeout):发送GET请求,并设置超时时间。

  • requests.get(url, verify=verify):发送GET请求,并设置SSL证书验证。

  • requests.get(url, allow_redirects=allow_redirects):发送GET请求,并设置是否允许重定向。

  • requests.get(url, stream=stream):发送GET请求,并设置是否使用流式传输

3.data/json/param参数传递

在使用requests库发送网络请求时,我们可以通过传递不同的参数来实现不同的请求方式和数据传递方式。常用的参数包括data、json和params。

1.data参数

data参数用于传递表单数据,通常用于POST请求。它可以是一个字典,也可以是一个字符串。如果是字典,requests会自动将其转换为表单形式;如果是字符串,则需要手动指定Content-Typeapplication/x-www-form-urlencoded

示例代码:

import requests

data = {
    'username': 'admin',
    'password': '123456'
}

response = requests.post('http://www.example.com/login', data=data)

2.json参数

json参数用于传递JSON格式的数据,通常用于POST请求。它可以是一个字典,也可以是一个字符串。如果是字典,requests会自动将其转换为JSON格式;如果是字符串,则需要手动指定Content-Typeapplication/json

示例代码:

import requests

data = {
    'username': 'admin',
    'password': '123456'
}

response = requests.post('http://www.example.com/login', json=data)

3.params参数

params参数用于传递URL参数,通常用于GET请求。它可以是一个字典,也可以是一个字符串。如果是字典,requests会自动将其转换为URL参数;如果是字符串,则需要手动拼接URL

示例代码:

import requests

params = {
    'page': 1,
    'size': 10
}

response = requests.get('http://www.example.com/articles', params=params)

4.隧道代理使用

隧道代理是一种通过隧道连接到代理服务器的方式来进行网络请求的方法。这种方式可以帮助我们隐藏真实的IP地址,提高爬虫的稳定性和安全性。

使用隧道代理需要先购买代理服务,然后在代码中设置代理服务器的IP地址和端口号。以下是一个使用隧道代理的示例代码:

import requests

proxy = {
    'http': 'http://代理服务器IP地址:端口号',
    'https': 'https://代理服务器IP地址:端口号'
}

url = 'https://www.example.com'
response = requests.get(url, proxies=proxy)

print(response.text)

在上面的代码中,我们首先定义了一个代理字典,包含了http和https两种协议的代理服务器地址和端口号。然后使用requests库的get方法发送请求时,将代理字典作为proxies参数传入即可。

需要注意的是,使用隧道代理可能会降低请求速度,而且代理服务的质量也会影响到爬虫的效果。因此,在选择代理服务时需要谨慎,建议选择稳定可靠的服务商。

5.证书异常处理

在进行网络请求时,有些网站会进行证书认证以确保数据的安全。如果requests库在进行SSL证书验证时遇到了问题,会抛出“证书验证异常(Certificate Verification Error)”的异常。这个异常通常是由于请求响应的SSL证书无效或不受信任导致的。

以下是requests库中处理证书异常的方法:

1.忽略证书验证

在使用requests库进行网络请求时,可以通过设置verify参数为False来忽略SSL证书验证。这个方法会禁止requests库对证书进行验证,而是采用不安全的方式进行通信,因此在进行敏感操作时应慎重使用。

例如:

response = requests.get('https://example.com', verify=False)

2.设置证书文件

可以通过设置cert参数来指定一个证书文件,在请求时使用该证书进行验证。这个方法需要事先获得一个有效的证书文件,如果无法提供有效证书则无法进行安全通信。

例如:

response = requests.get('https://example.com', cert=('path/to/cert.crt', 'path/to/key'))

3.添加自定义证书

可以通过requests库提供的certifi库在运行时初始化一个自定义证书,从而进行证书验证。这种方式需要提供证书的SHA256指纹值,并将其添加到requests库已有的证书列表中。

例如:

import certifi

cert = certifi.where()
fingerprints = {'example.com': 'A1:B2:C3:...', ...}
with open(cert, 'a') as f:
    for host, fingerprint in fingerprints.items():
        f.write(f'{host} {fingerprint}\n')

response = requests.get('https://example.com', verify=True)

在以上代码中,certifi.where()用于获取当前Python环境中的证书路径,然后将每个需要验证的主机和其证书的SHA256指纹添加到证书文件中。

综上,要避免证书异常需要注意常见的安全规则,如设置SSL证书验证、使用CA颁发的证书、对外不开放不安全的通信端口等。需要快速扫描设备,确保组件升级到最新版本,在安全上下文中测试企业所依赖的所有服务并采用有力的加密技术以支持加密通信。

二丶httpx

1.httpx源码解析

httpx是一个Python异步HTTP客户端库,它提供了简单易用的API,支持异步和同步请求,支持HTTP/1.1和HTTP/2协议,支持代理、SSL/TLS、Cookie等功能。下面我们来看一下httpx的源码解析。

httpx的核心代码在client.py文件中,其中最重要的是Client类。Client类是httpx的主要接口,它提供了发送HTTP请求的方法,如get、post、put、delete等。下面是Client类的定义:

class Client:
    def __init__(
        self,
        timeout=UNSET,
        follow_redirects=UNSET,
        max_redirects=UNSET,
        verify=UNSET,
        cert=UNSET,
        trust_env=UNSET,
        http2=UNSET,
        backend=UNSET,
        default_headers=UNSET,
        base_url=UNSET,
        app=UNSET,
        auth=UNSET,
        cookies=UNSET,
        allow_redirects=UNSET,
        proxies=UNSET,
        dispatch=UNSET,
        limits=UNSET,
        pool_limits=UNSET,
        retry=UNSET,
        trust_env_proxies=UNSET,
        headers=UNSET,
        **extra_options,
    ):
        ...

Client类的构造函数接受很多参数,这些参数可以用来配置httpx的行为。其中比较重要的参数包括:

  • timeout:请求超时时间。
  • follow_redirects:是否自动跟随重定向。
  • max_redirects:最大重定向次数。
  • verify:是否验证SSL证书。
  • cert:客户端证书。
  • trust_env:是否信任环境变量。
  • http2:是否启用HTTP/2协议。
  • backend:HTTP客户端后端。
  • default_headers:默认请求头。
  • base_url:基础URL。
  • app:ASGI应用程序。
  • auth:HTTP认证。
  • cookies:请求Cookie。
  • allow_redirects:是否允许重定向。
  • proxies:代理服务器。
  • dispatch:请求分发器。
  • limits:请求限制。
  • pool_limits:连接池限制。
  • retry:请求重试。
  • trust_env_proxies:是否信任环境变量中的代理服务器。
  • headers:请求头。

Client类的方法包括

  • request:发送HTTP请求。
  • get:发送GET请求。
  • post:发送POST请求。
  • put:发送PUT请求。
  • delete:发送DELETE请求。
  • head:发送HEAD请求。
  • options:发送OPTIONS请求。
  • patch:发送PATCH请求。
    这些方法都是基于request方法实现的,只是参数不同。下面是request方法的定义:
async def request(
    self,
    method,
    url,
    *,
    params=UNSET,
    data=UNSET,
    json=UNSET,
    headers=UNSET,
    cookies=UNSET,
    files=UNSET,
    auth=UNSET,
    timeout=UNSET,
    allow_redirects=UNSET,
    cert=UNSET,
    verify=UNSET,
    stream=UNSET,
    trust_env=UNSET,
    max_redirects=UNSET,
    http2=UNSET,
    backend=UNSET,
    dispatch=UNSET,
    limits=UNSET,
    pool_limits=UNSET,
    retry=UNSET,
    trust_env_proxies=UNSET,
    **options,
):
    ...

request方法接受很多参数,包括HTTP请求方法、URL、请求参数、请求体、请求头、请求Cookie、文件、HTTP认证、请求超时时间、是否允许重定向、客户端证书、是否验证SSL证书、是否使用流式传输、是否信任环境变量、最大重定向次数、是否启用HTTP/2协议、HTTP客户端后端、请求分发器、请求限制、连接池限制、请求重试、是否信任环境变量中的代理服务器等。

httpx的源码比较清晰,代码结构清晰,注释详细,易于阅读和理解。如果你想深入了解httpx的实现原理,可以阅读httpx的源码。

2.httpx常用方法

httpx是一个Python的异步HTTP客户端库,它提供了许多常用的方法来发送HTTP请求和处理响应。以下是httpx常用的方法:

  • get(url, params=None, **kwargs): 发送GET请求,url为请求的URL,params为请求参数,kwargs为其他可选参数,如headers、timeout等。

  • post(url, data=None, json=None, **kwargs): 发送POST请求,url为请求的URL,data为请求数据,json为请求的JSON数据,kwargs为其他可选参数,如headers、timeout等。

  • put(url, data=None, **kwargs): 发送PUT请求,url为请求的URL,data为请求数据,kwargs为其他可选参数,如headers、timeout等。

  • delete(url, **kwargs): 发送DELETE请求,url为请求的URL,kwargs为其他可选参数,如headers、timeout等。

  • head(url, **kwargs): 发送HEAD请求,url为请求的URL,kwargs为其他可选参数,如headers、timeout等。

  • options(url, **kwargs): 发送OPTIONS请求,url为请求的URL,kwargs为其他可选参数,如headers、timeout等。

  • request(method, url, **kwargs): 发送自定义请求,method为请求方法,url为请求的URL,kwargs为其他可选参数,如headers、timeout等。

  • close(): 关闭httpx客户端。

  • request_stream(method, url, **kwargs): 发送流式请求,method为请求方法,url为请求的URL,kwargs为其他可选参数,如headers、timeout等。

  • request_raw(method, url, **kwargs): 发送原始请求,method为请求方法,url为请求的URL,kwargs为其他可选参数,如headers、timeout等。

  • request_bytes(method, url, **kwargs): 发送字节请求,method为请求方法,url为请求的URL,kwargs为其他可选参数,如headers、timeout等。

  • request_json(method, url, **kwargs): 发送JSON请求,method为请求方法,url为请求的URL,kwargs为其他可选参数,如headers、timeout等。

  • request_text(method, url, **kwargs): 发送文本请求,method为请求方法,url为请求的URL,kwargs为其他可选参数,如headers、timeout等。

  • request_files(method, url, files=None, **kwargs): 发送文件请求,method为请求方法,url为请求的URL,files为上传的文件,kwargs为其他可选参数,如headers、timeout等。

  • request_multipart(method, url, data=None, files=None, **kwargs): 发送多部分请求,method为请求方法,url为请求的URL,data为请求数据,files为上传的文件,kwargs为其他可选参数,如headers、timeout等。

3.httpx上下文处理

在httpx中,上下文处理是指在一个请求中,将一些共同的参数或配置信息保存在一个上下文对象中,以便在后续的请求中使用。这样可以避免在每个请求中都重复设置相同的参数或配置信息,提高代码的可读性和可维护性。

httpx中的上下文对象是一个字典,可以通过创建一个httpx.Context对象来获取。在创建Context对象时,可以传入一些默认的参数或配置信息,这些信息会被保存在Context对象中,以便在后续的请求中使用。

下面是一些常用的httpx上下文处理方法:

1.创建Context对象

import httpx

context = httpx.Context()

2.设置默认的请求头

context.headers.update({
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
})

3.设置代理

context.proxies = {
    'http': 'http://127.0.0.1:8888',
    'https': 'http://127.0.0.1:8888'
}

4.设置超时时间

context.timeout = httpx.Timeout(10.0, read=20.0)

5.设置SSL验证

context.verify = False

6.设置cookie

context.cookies['name'] = 'value'

7.设置认证信息

context.auth = httpx.BasicAuth('username', 'password')

8.设置重试次数

context.retry = httpx.Retry(total=3, backoff_factor=0.3)

9.设置连接池

context.http2 = True
context.max_keepalive_connections = 100
context.max_connections = 100

10.在请求中使用Context对象

import httpx

context = httpx.Context()
context.headers.update({
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
})

with httpx.Client(context=context) as client:
    response = client.get('https://www.example.com')

4.httpx异步请求

在进行网络请求时,有时候需要进行异步请求,以提高效率和性能。httpx是一个支持异步请求的Python HTTP客户端库,可以使用async/await语法进行异步请求。

下面是一个使用httpx进行异步请求的示例:

import httpx
import asyncio

async def fetch(url):
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        return response.text

async def main():
    urls = [
        'https://www.baidu.com',
        'https://www.google.com',
        'https://www.bing.com'
    ]
    tasks = [asyncio.create_task(fetch(url)) for url in urls]
    results = await asyncio.gather(*tasks)
    print(results)

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

在上面的示例中,我们定义了一个fetch函数,用于异步请求指定的URL,并返回响应内容。然后在main函数中,我们定义了三个URL,使用asyncio.create_task创建了三个异步任务,并使用asyncio.gather等待所有任务完成,并打印结果。

需要注意的是,在使用httpx进行异步请求时,需要使用AsyncClient类,而不是普通的Client类。此外,需要使用async/await语法进行异步请求。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容