数据获取:​如何让爬虫更健壮

2023-09-02 08:04:24 浏览数 (1)

在昨天的demo中的代码还有一个问题就是,假如某个地方出错了怎么办,可能是网络掉线了,可能是某一次请求被拦截了,那么会造成程序直接停掉了。数据量小的爬虫还可以找到错误,重新启动,如果是数据量大的,重跑会造成时间、空间等资源的浪费。所以我们还需要对这个爬虫进行一些改造,增加一些异常处理,使其更加强大。

其中有几处代码中添加了time.sleep(2)方法,这句话作用是当前线程暂停两秒,目的是为了降低当前IP的请求频率,从而绕过反爬。其实很多网站为了防止流量攻击,如果检测到某个IP短时间内发送了大量请求,那么此IP后续一段时间内的请求将不能得到正确的响应。

在这个例子中,仅仅是抓取250条信息,时间还好。如果需要抓取25000条,那么这样的方式在时间上要100倍,肯定效率太慢了,那还有什么方法呢?

接下来我们就了解一下爬虫的异常处理以及常见的反扒措施。

异常处理

规划异常处理也是爬虫中比较重要的一环,好的异常处理会给一个好的数据结果打好基础。这就关系到异常处理的刻度的问题,可以分为以下几种常见场景的处理方式。

1.只在main方法中添加异常处理

优点:方法简单,添加容易

缺点:颗粒度太粗,只能保证程序运行,数据质量可能会不高

2.在requests请求上添加异常处理

优点:可以捕获请求的异常

缺点:颗粒度适中,无法排除因为原始数据质量差而造成的异常

3.在requests请求和数据操作上都添加异常处理

优点:颗粒度细,最大限度保证数据质量

缺点:需要添加的异常处理内容太多

最后在添加异常处理的位置上,还是需要看具体的需求来定,对每一条数据元素的重要性进行排序,可以在重要数据中添加异常处理,如果发生异常选择跳过或者使用默认值,以此可以最大限度保证数据的完整性。

代理IP

代理IP其实是就是代理服务器,它的作用就是相当于跑腿的,帮你去取得网络信息。它是网络信息的中转站。

一个形象的比喻,某一家店卖的东西特别好吃,但是有一个要求是一个用户每年只能买三个,这时候你吃了三个还想吃,怎么办,那就让外卖小哥来帮你去买,这个时候店家一看,来的不是同一个人,那就卖给外卖小哥,外卖小哥最后送给了谁,店家并不知道。这时候外卖小哥的作用就是一个代理服务器的作用,只是作为来一个请求的转发。

对于爬虫程序来说,因为是机器处理,所以访问速度会非常快,很多应用服务器都会对IP进行限制,如果一定时间内超过了允许的阈值,那么将不会对此IP发送来的请求进行响应。代理IP就通过转发请求来进行访问,这样应用服务器并不能知道真实的访问IP是多少,不会触发反爬机制。

现在很多的市面上很多的代理服务商,都会有自己的代理服务器,帮助用户来转发请求,当然这些代理服务器也是付费使用的,而且使用代理IP上也有一定的规则和存活时间。

代理IP类型中也分为透明、匿名、高匿三种,透明的代理在对方服务器中可以获取到真实的请求IP,好比是商家虽然知道来取货的是外卖小哥,但是购买方并不是外卖小哥一样,高匿的代理IP的会隐藏自己的真实IP,服务器很难找到真实的请求IP。

目前市面上很多的代理服务商也推出了一些隧道代理IP的服务,即是代理服务商自己对请求进行了封装和转发,并且对用户提供一个Api接口,用户只需要将自己的请求的地址、参数、请求方式以及代理商的认证等信息发到Api接口中,直接获取返回的内容即可。对于用户来说,并不需要知道当前的请求是发送到哪个IP的,只需要关心请求是否可以返回成成功即可。

因为每一家代理服务商都有自定义的代理IP使用方式,并且在购买了相关的服务后,会提供相关的使用说明,这里就不一一解释说明。如果碰到需要使用代理IP的场景,可以自行搜索一些代理服务商购买一些服务。

正则表达式

正则表达式(regular expression)是一种字符串匹配的模式,有自身特定的语法,很多时候在爬虫中是使用正则来查找符合要求的字符串。下面是爬虫中常用的正则字符和其含义。

类型

字符

含义

元字符

^

匹配行或者字符串的开头

$

匹配行或字符串的结尾

d

匹配数字

w

匹配字母,数字,下划线

.

匹配除了换行符以外的任何字符

s

匹配空格

[abc]

匹配包含括号内元素的字符

量词

*

重复零次或多次

重复一次或多次

?

重复零次或一次

{n}

重复n次

{n,m}

重复n-m次

写好正则并不是一个容易的事情,因为匹配同一个字符串可以有多种写法,但是一条正则表达式,可能匹配了多个结果,可能会掺杂一些我们并不想要的结果。在刚开始接触的正则的时候需要慢慢的摸索,拿出其中一个页面来做测试,直到最后数据效果满意后再应用于其他页面。

在Python中,re 模块包含了全部正则语法的功能,下面介绍爬虫中常用的re模块的方法。

re.match()

函数参数:re.match(pattern, string, flags=0),pattern是正则表达式,string为字符串,flags是模式标志位,比如设置是否大小写敏感等等。

此方法用来从开头位置查找是否满足匹配条件的字段串,如果没有配置成功返回None,如果有,则会返回一个包含对应结果值的对象,可以用group()方法进行查看。

代码语言:javascript复制
import re
#待匹配的字符串---以数字开头
text = "123abc"
#匹配是否数字开头
res = re.match("d", text)
print(res)
print(res.group())

代码结果:

代码语言:javascript复制
<re.Match object; span=(0, 1), match='1'>
1

re.search()

参数跟match()一样,不同的是search()会搜索整个字符串,直到找到第一个匹配的字符串。而match()仅仅只是最开头做匹配,返回值也是一个对象,可以用group(num)或groups()方法进行查看。

代码语言:javascript复制
import re
#待匹配的字符串---以字母开头
text = """abc123"""
res = re.search("d", text)
print(res)
print(res.group())

代码结果:

代码语言:javascript复制
<re.Match object; span=(3, 4), match='1'>
1

re.findall()

参数跟上面两个方法一样,findall()查找所有正则表达式的所有结果,并且直接返回的结果列表,对象是list。

代码语言:javascript复制
import re
#待匹配的字符串---以字母开头
text = """abc123"""
res = re.findall("d", text)
print(res)

代码结果:

代码语言:javascript复制
['1', '2', '3']

re. compile ()

函数参数:compile(pattern,flag=0),compile()函数的作用是编译正则表达式,返回一个正则表达式对象。

代码语言:javascript复制
import re
# 编译Pattern对象
res = re.compile("d")
print(type(res))

代码结果:

代码语言:javascript复制
<class 're.Pattern'>

Pattern对象中也有上述三种常用的方法,其实上述三个方法已经在方法内执行了compile()的过程,以search()为例子,源码中是这样写的:

代码语言:javascript复制
def search(pattern, string, flags=0):
    return _compile(pattern, flags).search(string)

本节内容中,我们主要是数据来源,重点了解网络数据的爬取,通过Python中丰富的库可以快速的帮助搭建起爬虫,来获取网上公开的数据。当然在爬虫方面还有很多内容,比如说验证码识别、登录状态的维护等等,但是最终还是以HTML文本或者JSON字符串的形式获取到数据,用于后续的内容。

我们也能发现,不管是BeautifulSoup还是lxml都是只能针对于特定的页面有作用,如果数据源改变了,那么后续的内容都无法生效。所以在后面的数据获取时候还是需要多多探索,并不没有一招吃遍天的招式。

0 人点赞