昨天一起玩游戏的一位老哥找到我,问我可不可以写一个爬取百度贴吧中有关回收中石化刮刮卡并且包含手机号码信息的爬虫。心想那个时候我第一时间想到了 bs4 的 find_all(),应该这种先入为主的思想让我走过了很多弯路。
再次领略正则表达式的便利
- 基本思路
- 走过的弯路
- 过于喜欢遍历,以至于很浪费时间(此时还没有考虑内存的思想)
- 保存信息时,忽略编码格式造成乱码
- 处理异常能力不强
- 正则表达式的优势
- 规规矩矩,只找出符合格式的信息
- 正则表达式的劣势
- 匹配规则需要十分严谨
- 总结
基本思路
先看一看所需内容的大概结构
大概可以看作网页以一个列表的形式展现信息即每一篇文章的信息都存放在一个 li节点中
思路:获取每篇文章的url —> 下载并分析每篇文章的源码 —> 筛选每位用户发表信息 —> 匹配手机号码 —> 保存信息到本地
走过的弯路
过于喜欢遍历,以至于很浪费时间(此时还没有考虑内存的思想)
依赖于 for 循环,在匹配手机号码时,采用了最笨的一种方法
words = '油卡中石化刮刮充值卡,信誉有保障,有兴趣的来撩,北京号称几十亿的大资方回避,居间人勿扰,诚信做的咨询!联系方式:13703756542'
phone_num = 0
for i in range(len(words)):
if words[i].isalnum():
if phone_num == 0:
if words[i + 1].isalnum()
phone_num += 1
if phone_num != 0:
if words[i - 1].isalnum():
phone_num += 1
else:
phone_num == 1
if phone_num == 10:
# 手机号码都是十一位,注意phone_num 从0开始计数,故表示如果文段中包含11位的数字,就保存信息
with open('./record.txt','a') as record:
record.write(words + '\n')
保存信息时,忽略编码格式造成乱码
可以看到上一小节内容中有这样的两行文字
with open('./record.txt','a') as record:
record.write(words + '\n')
至于编码格式我没有进行研究过。大多时候我在保存信息时并没有加上 encoding = ‘xxx’ 这样的一句话,也并没有因此造成存入的信息为乱码。只遇到过读取信息时不加编码格式会出现乱码。
with open('./record.txt','a',encoding = 'utf-8') as record:
record.write(words + '\n')
无论是否研究过编码格式,养成一个无论读取都要指定编码格式的习惯,也会少走一些小弯路。
处理异常能力不强
如果搜一下爬虫,全称叫做网络爬虫。顾名思义,爬虫靠得就是网络。那问题到我这儿就真是个问题了,家里网络有时候会有波动,会连不上网,但是对于网络出现的链接不到人家的服务器,我就只会
for page_html in page_htmls:
try:
parse_html()
except:
time.sleep(3)
continue
这样造成的结果就是可能把某个帖子跳过去,然而又恰好这个帖子中有你需要的信息,又恰好这份信息会带来效益。。。你看,不会处理异常,亏不亏?
正则表达式的优势
规规矩矩,只找出符合格式的信息
words = '油卡中石化刮刮充值卡,信誉有保障,有兴趣的来撩,北京号称几十亿的大资方回避,居间人勿扰,诚信做的咨询!联系方式:13703756542'
phone_number = re.findall(r'1\d\d\d\d\d\d\d\d\d\d',words)
# phone_num = re.findall(r'1\d*10')
# 喜欢用第一个方法,因为我对数字不敏感,第一个虽然麻烦点儿,但是很直观,但是缺点是纠错时要一个一个查,很麻烦
与上方笨方法相比,减少了不知多少篇幅,节省了不知多少时间
附加正则匹配规则表一张
正则表达式的劣势
匹配规则需要十分严谨
之前写过一个爬取小红书视频的爬虫,那时候还没学xpath、bs4、pyquery 只接触了正则表达式
先看一个例子吧
def down_video(self,*s1):
try:
self.flag += 1
lis1 = [""]
for i in s1:
lis1[0] += i
response = requests.get(lis1[0],headers=self.headers)
time.sleep(1)
html = response.text
url = re.findall('<video poster=".*?" src="(.*?)" controls=".*?" objectFit=".*?" class=".*?" ', html)
title = re.findall('<meta property="og:title" content="(.*?)">', html)
lis1 = []
start = url[0].find("amp;")
lis1.append(url[0][:start])
lis1[0] += url[0][start + 4:]
url = lis1[0]
response = requests.get(url, headers=self.headers)
with open("D:/小红书视频/" + title[0] + '.mp4', 'wb') as f:
f.write(response.content)
except urllib.error.URLError as e:
print(e.reason())
这是当时用纯正则匹配出来的url,可以看到这样的两行内容
url = re.findall('<video poster=".*?" src="(.*?)" controls=".*?" objectFit=".*?" class=".*?" ', html)
title = re.findall('<meta property="og:title" content="(.*?)">', html)
在匹配 url 时,原标签页不只是
<video poster=".*?" src="(.*?)" controls=".*?" objectFit=".*?" class=".*?" '
在class后还有很多个属性,当时也是处于懵懂的状态,认为匹配可以将那些相同的属性删去,所以尝试过很多次都失败告终
失败时的写法:
url = re.findall('<video poster=".*?" src="(.*?)" controls=".*?" objectFit=".*?" class=".*?" '>, html)
仔细看就可以看到与正确写法只相差一个 > ,正因为这样的一个 > 符号,让我对正则表达式有了一份忌惮,以至于在写过这个小红书爬虫后再也没有用过正则表达式
总结
在筛选信息时,不要太依赖于更高级别,更方便的解析器。就像美某国一样,科技的确很发达,但是基础制造业很是平凡,离开中国,还不是算个der