[爬虫]3.基本库的使用

使用 urllib

首先,了解一下 urllib 库,它是 Python 内置的 HTTP 请求库,也就是说不需要额外安装即可使用。它包含如下 4 个模块。

  • request:它是最基本的 HTTP 请求模块,可以用来模拟发送请求。就像在浏览器里输入网址然后回车一样,只需要给库方法传入 URL 以及额外的参数,就可以模拟实现这个过程了。

  • error:异常处理模块,如果出现请求错误,我们可以捕获这些异常,然后进行重试或其他操作以保证程序不会意外终止。

  • parse:一个工具模块,提供了许多 URL 处理方法,比如拆分、解析、合并等。

  • robotparser:主要是用来识别网站的 robots.txt 文件,然后判断哪些网站可以爬,哪些网站不可以爬,它其实用得比较少。

发送请求

urlopen

  • 构造方法

    urllib.request.urlopen(url, data=None, [timeout,]-, cafile=None, capath=None, cadefault=False, context=None)
  • 基本使用

    import urllib.request
    
    response = urllib.request.urlopen('https://www.python.org')
    # 获取返回类型
    print(type(response))
    # 获取返回结果的状态码
    print(response.status)
    # 获取响应头的各数据
    print(response.getheaders())
    # 获取了响应头中的 Server 值,结果是 nginx,意思是服务器是用 Nginx 搭建的。
    print(response.getheader('Server'))
    #获取读取信息,即网页的源代码
    print(response.read().decode('utf-8'))
  • data参数 将参数转化为字节流编码格式的内容,即 bytes 类型,POST请求方式

    import urllib.parse  
    import urllib.request  
    
    # 获取hello!xxz,会传送到运行结果的word --POST模拟表单获取
    #  urlencode 方法来将参数字典转化为字符串
    data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf8')  
    response = urllib.request.urlopen('http://httpbin.org/post', data=data)  
    print(response.read())
  • timeout参数

    用于设置超时时间,单位为秒;如果请求超出了设置的这个时间,还没有得到响应,就会抛出异常

    可以通过设置这个超时时间来控制一个网页如果长时间未响应,就跳过它的抓取

    import socket  
    import urllib.request  
    import urllib.error  
    
    try:  
        response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)  
    except urllib.error.URLError as e:  
        # socket.timeout --超时异常
        if isinstance(e.reason, socket.timeout):  
            print('TIME OUT')
  • 其他参数

    context 参数,它必须是 ssl.SSLContext 类型,用来指定 SSL 设置

    ......

    详见文档:urllib.request — 用于打开 URL 的可扩展库 — Python 3.11.4 文档

Requset[power!]

如果请求中需要加入 Headers 等信息,就可以利用更强大的 Request 类来构建

  • Request构造方法

    • url 用于请求 URL,这是必传参数,其他都是可选参数。

    • data 如果要传,必须传 bytes(字节流)类型的。如果它是字典,可以先用 urllib.parse 模块里的 urlencode() 编码。

    • headers 是一个字典,它就是请求头,我们可以在构造请求时通过 headers 参数直接构造,也可以通过调用请求实例的 add_header() 方法添加。

    • unverifiable 表示这个请求是否是无法验证的,默认是 False,意思就是说用户没有足够权限来选择接收这个请求的结果。例如,我们请求一个 HTML 文档中的图片,但是我们没有自动抓取图像的权限,这时 unverifiable 的值就是 True。

    • method 是一个字符串,用来指示请求使用的方法,比如 GET、POST 和 PUT 等。

  • 初步使用

power!

  • Handler

    把它理解为各种处理器,有专门处理登录验证的,有处理 Cookies 的,有处理代理设置的。利用它们,我们几乎可以做到 HTTP 请求中所有的事情

    父类BaseHandler,各种子类:

    • HTTPDefaultErrorHandler 用于处理 HTTP 响应错误,错误都会抛出 HTTPError 类型的异常。

    • HTTPRedirectHandler 用于处理重定向。

    • HTTPCookieProcessor 用于处理 Cookies。

    • ProxyHandler 用于设置代理,默认代理为空。

    • HTTPPasswordMgr 用于管理密码,它维护了用户名密码的表。

    • HTTPBasicAuthHandler 用于管理认证,如果一个链接打开时需要认证,那么可以用它来解决认证问题。

  • OpenerDirector 就是利用 Handler 来构建 Opener

    • 验证

    • 代理

    • Coookies

      • 在爬虫中处理 Cookies

      • 从网站获取并使用 Cookies

      • 将 Cookies 保存到文件中以供后续使用

处理异常

URLError

打开一个不存在的页面,照理来说应该会报错,但是这时我们捕获了 URLError 这个异常,运行结果如下:

程序没有直接报错,而是输出了如上内容,这样通过如上操作,我们就可以避免程序异常终止,同时异常得到了有效处理。

HTTPError

URLError 的子类,专门用来处理 HTTP 请求错误,比如认证请求失败等。它有如下 3 个属性。

  • code:返回 HTTP 状态码,比如 404 表示网页不存在,500 表示服务器内部错误等

  • reason:同父类一样,用于返回错误的原因

  • headers:返回请求头

示例:

运行结果:

结合使用

因为 URLError 是 HTTPError 的父类,所以可以先选择捕获子类的错误,再去捕获父类的错误

先捕获 HTTPError,获取它的错误状态码、原因、headers 等信息。如果不是 HTTPError 异常,就会捕获 URLError 异常,输出错误原因。最后,用 else 来处理正常的逻辑。这是一个较好的异常处理写法。

reason返回字符串

reason返回对象

运行结果如下:

解析链接

urlparse -解析URL

  • 构造方法

    3 个参数:

    • urlstring:这是必填项,即待解析的 URL。

    • scheme:它是默认的协议(比如 http 或 https 等)。假如这个链接没有带协议信息,会将这个作为默认的协议。

      scheme 参数只有在 URL 中不包含 scheme 信息时才生效。如果 URL 中有 scheme 信息,就会返回解析出的 scheme

    • allow_fragments:即是否忽略 fragment。如果它被设置为 False,fragment 部分就会被忽略,它会被解析为 path、parameters 或者 query 的一部分,而 fragment 部分为空。

  • 实现 URL 的识别和分段

    运行结果如下:

  • 返回结果是一个 ParseResult 类型的对象, 它包含 6 个部分,分别是 scheme、netloc、path、params、query 和 fragment。可以得出一个标准的链接格式,具体如下: scheme://netloc/path;params?query#fragment

  • 返回结果 ParseResult 实际上是一个元组 我们可以用索引顺序来获取,也可以用属性名获取。示例如下:

    分别用索引和属性名获取了 scheme 和 netloc,其运行结果如下:

urlunparse -构造URL

有了 urlparse 方法,相应地就有了它的对立方法 urlunparse。它接受的参数是一个可迭代对象,但是它的长度必须是 6,否则会抛出参数数量不足或者过多的问题。先用一个实例看一下:

这里参数 data 用了列表类型。也可以用其他类型,比如元组或者特定的数据结构。运行结果如下:

urlsplit -解析URL

它不再单独解析 params 这一部分,只返回 5 个结果, params 会合并到 path 中

运行结果如下:

返回结果是 SplitResult,也是一个元组类型,既可以用属性获取值,也可以用索引来获取

urlunsplit -构造URL

与 urlunparse 方法类似,它也是将链接各个部分组合成完整链接的方法,传入的参数也是一个可迭代对象,例如列表、元组等,唯一的区别是长度必须为 5。

示例如下:

运行结果如下:

urljoin -解析URL

提供一个 base_url(基础链接)作为第一个参数,将新的链接作为第二个参数,该方法会分析 base_url 的 scheme、netloc 和 path 这 3 个内容并对新链接缺失的部分进行补充,最后返回结果。

示例:

运行结果:

urlencode -转GET请求参数

示例:

这里首先声明了一个字典来将参数表示出来,然后调用 urlencode 方法将其序列化为 GET 请求参数。运行结果如下:

这个方法非常常用。有时为了更加方便地构造参数,我们会事先用字典来表示。要转化为 URL 的参数时,只需要调用该方法即可。

parse_qs -转字典

利用 parse_qs 方法,就可以将它转回字典,示例如下:

运行结果如下:

parse_qsl -转元组

将参数转化为元组组成的列表,示例如下:

运行结果如下:

quote -URL 编码

将内容(中文)转化为 URL 编码的格式

示例如下:

这里我们声明了一个中文的搜索文字,然后用 quote 方法对其进行 URL 编码,最后得到的结果如下:

unquote --URL 解码

进行 URL 解码,示例如下:

这是上面得到的 URL 编码后的结果,这里利用 unquote 方法还原,结果如下:

分析Robots

Robots 协议

Robots 协议也称作爬虫协议,用来告诉爬虫和搜索引擎哪些页面可以抓取,哪些不可以抓取。它通常是一个叫作 robots.txt 的文本文件,一般放在网站的根目录下。

爬虫名称

一些常见搜索爬虫的名称及其对应的网站

爬虫名称
名  称
网  站

BaiduSpider

百度

www.baidu.com

Googlebot

谷歌

www.google.com

360Spider

360 搜索

www.so.com

YodaoBot

有道

www.youdao.com

ia_archiver

Alexa

www.alexa.cn

Scooter

altavista

www.altavista.com

robotparser

使用 robotparser 模块来解析 robots.txt

  • 构造方法 (very easy啦

  • 模块常用方法

    • set_url :用来设置 robots.txt 文件的链接

    • read:读取 robots.txt 文件并进行分析,一般为ture

    • parse:用来解析 robots.txt 文件

    • can_fetch:该方法传入两个参数 User-agent& URL。返回的内容是该搜索引擎是否可以抓取这个 URL,返回结果是 True 或 False

    • mtime:返回的是上次抓取和分析 robots.txt 的时间

    • modified:将当前时间设置为上次抓取和分析 robots.txt 的时间

request和urllib的区别

  • urllib 是Python标准库中的模块,不需要安装额外的包

  • request是一个三方库,它在urllib的基础上提供了更简洁、更高级的接口和功能。requests库的设计目标是提供更人性化的API,使发送HTTP请求变得更加简单和方便。它支持更多的HTTP功能,例如自动处理重定向、会话管理、上传文件、处理Cookies等

  • 需要进行HTTP请求的基本操作,学习和使用requests库会更加便捷和高效。如果你对Python标准库感兴趣,或者有特定的需求需要使用urllib的功能,也可以深入学习urllib库。

  • 需要进行HTTP请求的基本操作,学习和使用requests库会更加便捷和高效。如果你对Python标准库感兴趣,或者有特定的需求需要使用urllib的功能,也可以深入学习urllib库。

使用 requests

基本用法

GET请求方法:

  • 基本用法

    调用 get 方法得到一个 Response 对象,然后分别输出了 Response 的类型、状态码、响应体的类型、内容以及 Cookies。

  • 利用 params 参数附加额外信息

    请求的链接自动被构造成了:http://httpbin.org/get?age=22&name=germey

  • 获取图片、音频和视频文件

其他请求方法:

  • 直接 .请求方法

  • POST请求方法示例

    运行结果的 form 部分就是提交的数据,这就证明 POST 请求发送成功

响应

下面列出了返回码和相应的查询条件:

高级用法

文件上传

cookies

  • 获取cookies

  • 设置cookies并维持登录状态

  • 使用Cookies参数设置Cookies的方法

    新建一个 RequestCookieJar 对象-->将复制下来的 cookies 利用 split 方法分割-->利用 set 方法设置好每个 Cookie 的 key 和 value-->通过调用 requests 的 get() 方法并传递给 cookies 参数【可以但没必要?】

会话维持

会话维持是指在进行多个请求时,保持相同的会话状态,而不是每个请求都创建一个新的会话。

解决问题::第一个请求使用post方法登录了一个网站,然后想要获取登录后的个人信息,你再次使用get方法请求个人信息页面。实际上,这相当于在两个独立的会话中操作,它们并不相关,所以无法成功获取个人信息。

有一种解决方法是在每次请求时手动设置相同的Cookies,但这样做非常麻烦。我们有更简单的解决方法,那就是使用Session对象。

Session对象可以方便地维护一个会话,并自动处理Cookies的问题。通过创建一个Session对象,我们可以在同一个会话中发送多个请求,会话对象会自动处理Cookies的传递和存储。

运行结果:(运行的好慢,建议直接点进网址)

SSL 证书验证

当发送 HTTP 请求的时候,requests 会提供验证SSL 证书功能。通过verify参数控制是否验证证书,默认情况下verifyTrue,会自动验证证书。

指定本地证书用作客户端证书:

代理设置

  • proxies参数

  • 使用 HTTP Basic Auth

  • SOCKS 协议的代理 pip3 install "requests[socks]"

超时设置

timeout参数

身份认证

OAuth 认证 pip3 install requests_oauthlib

Prepared Request

目的:

  1. 请求定制化:可以设置请求的URL、请求方法、请求数据、请求头、超时时间等各种参数,以满足具体的需求

  2. 请求队列调度:可以将多个Prepared Request对象放入队列中,并按照一定的策略进行调度和发送,实现批量处理请求、并发请求、异步请求等功能,提高请求的效率和性能

  3. 会话状态保持:在一个会话中,你可以发送多个请求,并共享会话级别的参数,如cookies、认证信息等。这对于模拟登录、进行会话管理以及处理需要会话保持的操作非常有用

构造Prepared Request对象 -- 发送Prepared Request

运行结果如下:

正则表达式

常用的匹配规则

模  式
描  述

\w

匹配字母、数字及下划线

\W

匹配不是字母、数字及下划线的字符

\s

匹配任意空白字符,等价于 [\t\n\r\f]

\S

匹配任意非空字符

\d

匹配任意数字,等价于 [0-9]

\D

匹配任意非数字的字符

\A

匹配字符串开头

\Z

匹配字符串结尾,如果存在换行,只匹配到换行前的结束字符串

\z

匹配字符串结尾,如果存在换行,同时还会匹配换行符

\G

匹配最后匹配完成的位置

匹配一个换行符

匹配一个制表符

^

匹配一行字符串的开头

$

匹配一行字符串的结尾

.

匹配任意字符,除了换行符,当 re.DOTALL 标记被指定时,则可以匹配包括换行符的任意字符

[...]

用来表示一组字符,单独列出,比如 [amk] 匹配 a、m 或 k

[^...]

不在 [] 中的字符,比如 [^abc] 匹配除了 a、b、c 之外的字符

*

匹配 0 个或多个表达式

+

匹配 1 个或多个表达式

?

匹配 0 个或 1 个前面的正则表达式定义的片段,非贪婪方式

{n}

精确匹配 n 个前面的表达式

{n, m}

匹配 n 到 m 次由前面正则表达式定义的片段,贪婪方式

a

b

( )

匹配括号内的表达式,也表示一个组

match :从头找

匹配目标

如果匹配,就返回匹配成功的结果;如果不匹配,就返回 None

运行结果如下:

通用匹配(./*)

.(点)匹配任意字符

*(星)匹配前面的字符无限次

组合在一起就可以匹配任意字符( •̀ ω •́ )y

贪婪与非贪婪

.*:贪婪匹配,匹配尽可能多字符

.*?:非贪婪匹配,匹配尽量少字符

在做匹配的时候字符串中间尽量使用非贪婪匹配,以避免出现匹配结果缺失的情况

修饰符

修饰符
描  述

re.I

使匹配对大小写不敏感

re.L

做本地化识别(locale-aware)匹配

re.M

多行匹配,影响 ^ 和 $

re.S

使。匹配包括换行在内的所有字符

re.U

根据 Unicode 字符集解析字符。这个标志影响 \w、\W、\b 和 \B

re.X

该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解

在网页匹配中,较为常用的有 re.S 和 re.I

转义匹配 \

search :找一个

在匹配时会扫描整个字符串,然后返回第一个成功匹配的结果

findall :找全部

返回列表类型,遍历获得每组内容

sub :删除

删除匹配到的文本

compile :复用

将正则字符串编译成正则表达式对象,相当于做了一层封装,以便服用

方法技巧

在做匹配的时候,字符串中间尽量使用非贪婪匹配

match:更适合用来检测某个字符串是否符合某个正则表达式的规则

search:匹配方便

findall:要提取多个内容时

案例:抓取猫眼电影排行

先浅写一个思路

目标

提取出猫眼电影 TOP100 的电影名称、时间、评分、图片等信息,提取的站点 URL 为 http://maoyan.com/board/4,提取的结果会以文件形式保存下来。

分析

http://maoyan.com/board/4?offset=10 的offset 代表偏移量值

开始写代码

存在的问题:

  1. 首页验证码登录 --请求头添加cookies

  2. 添加了反爬虫-验证拼图-暂未解决

    用selenium打开浏览器,进行了11-50页面的滑动验证,能保证代码继续运行,但是11-50的数据没有获得【?】

    运行结果:image-20230612220406176

最后更新于