爬虫中的正则表达式

写在前面

为了不浪费大家时间,首先声明两点:

  • 在第一篇文章:简单网站爬虫的所有技能(requests+bs4)涉及到的技能,不会重复讲解
  • 这篇文章不会涉及任何正则表达式基础内容,只会有新鲜的实战部分,请在《爬虫中的正则表达式—后传》写完之前,自学正则表达式基础内容
    • 比如\d表示数字
    • * 表示重复0或多次
    • ……
    • 对,只用了解概念就行了,所以不要太紧张

建议爬虫初学者做完简单网站爬虫的所有技能(requests+bs4)思考题。

  • 如无必要,勿增实体
  • 用正确的工具,做正确的事情

正则表达式是你掌握简单网站爬虫之后的进阶技能,如果requests+bs4就可以满足需求,为什么自己要平添烦恼。

为什么要用正则

因为遇到了棘手的问题,不然谁会去学这么难懂的正则表达式

今天爬取的网址是:为知笔记吧首页,爬取的内容是回复数
STOP!别点上面的文字,点击文字的时候,用简单网站爬虫的所有技能(requests+bs4)提到的检查元素工具看看文字背后的真实url,这是一个非常好的上网习惯。检查了之后,接着往下看。

(注:与为知笔记无任何利益相关)

找到回复数

非常好!你已经找到了它

(动态图只默认播放一次,嗯,我录制的时候点错了一个选项。但是解决也很简单,比如
PC:在图片上右键,点击”在新标签页中打开图片“
APP:点一下图片)

爬取网页源代码

看看网页源代码是不是真的包含了我们要的内容—回复数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding: utf-8 -*-
__author__ = 'duohappy'

import requests
from bs4 import BeautifulSoup

headers = {"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36'}
url = "http://tieba.baidu.com/f?kw=%E4%B8%BA%E7%9F%A5%E7%AC%94%E8%AE%B0"

web_data = requests.get(url, headers=headers)

# 新知识点 web_data.content
# 以字节的方式访问web_data,所以用'wb'模式写入
with open('tieba_text.txt', 'wb') as f:
f.write(web_data.content)

开心!网页源代码包含我们想要的内容

搬出BeautifulSoup

网页源代码里包含了回复数,那么我们来用css selector语法把内容提取出来吧。稍等,看看soup里有没有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# -*- coding: utf-8 -*-
__author__ = 'duohappy'

import requests
from bs4 import BeautifulSoup

headers = {"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36'}
url = "http://tieba.baidu.com/f?kw=%E4%B8%BA%E7%9F%A5%E7%AC%94%E8%AE%B0"

web_data = requests.get(url, headers=headers)

web_data.encoding = 'utf-8'
web_text = web_data.text

soup = BeautifulSoup(web_text, 'lxml')

with open('soup_text.txt', 'w') as f:
f.write(str(soup)) # soup对象转成字符串

很遗憾!soup里没有"肉"

到此,我们要学正则表达式了!用正确的工具,做正确的事

收集建议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- coding: utf-8 -*-
__author__ = 'duohappy'

import re

import requests
from bs4 import BeautifulSoup

headers = {"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36'}
url = "http://tieba.baidu.com/f?kw=%E4%B8%BA%E7%9F%A5%E7%AC%94%E8%AE%B0"

web_data = requests.get(url, headers=headers)
web_data.encoding = 'utf-8'
web_text = web_data.text

reply_nums = re.findall(r'(?<="回复">)[\s\S]*?(?=</span>)', web_text)
print(reply_nums)

正则表达式热身

正则表达式的心法

文章不涉及招式的讲解,需要自学正则表达式基础内容如零宽断言、懒惰模式、贪婪模式等

First Time

最容易理解的一个想法,也就是re.search()的用法: 扫描整个字符串并返回第一个成功的匹配

爬取帖子的创建时间,观察网页结构,写出匹配时间的正则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# -*- coding: utf-8 -*-
__author__ = 'duohappy'

import re

import requests

headers = {"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36'}

url = "https://tieba.baidu.com/p/5054019406"

web_data = requests.get(url, headers=headers)
web_data.encoding = 'utf-8'
source_code = web_data.text

## 匹配时间的正则
time_pattern = r'\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}'
# 匹配第一个时间
create_time = re.search(time_pattern, source_code).group()

print(create_time)

Focus

反复聚焦

匹配帖子创建者的用户名,可以先想一想怎么匹配,再读源代码
如果你对网页结构敏感性越高,那么写出的正则适用性越大,通过检查元素,发现用户名存在于一段html代码中,这段代码有一个class,class=”d_name”,d_name有什么含义?嘿嘿嘿

1
2
3
4
5
<li class="d_name" data-field="{"user_id":1081331744}">

<a data-field="{"un":"suoai1335"}" alog-group="p_author" class="p_author_name j_user_card" href="/home/main?un=suoai1335&ie=utf-8&fr=pb" target="_blank">suoai1335</a>

</li>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# -*- coding: utf-8 -*-
__author__ = 'duohappy'

import re

import requests

headers = {"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36'}

url = "https://tieba.baidu.com/p/5054019406"

web_data = requests.get(url, headers=headers)
web_data.encoding = 'utf-8'
source_code = web_data.text

# 匹配包含用户名正则表达式
include_username_pattern = r'(?<=<li class="d_name"\sdata)[\s\S]*?(?=</a>)'
# 匹配出来包含用户名的html代码
include_username = re.search(include_username_pattern, source_code).group()
# 匹配用户名的正则表达式
username_pattern = r'(?<=target="_blank">)[\s\S]*'
# First Time
username = re.search(username_pattern, include_username).group()

print(username)

下面用动画来演示一下,一般我们容易掉进一个误区里,认为要匹配什么,就只写匹配内容的正则表达式,可是呢?这个正则表达式又很难写,写完了又不是很通用,这个时候可以考虑换一种思路,发散一下思维,写一个正则表达式来匹配更多的内容,然后针对这一内容,再写一个正则表达式,最终取得自己想要的内容。

注:看看评论

参考资料

正则表达式30分钟入门教程

感谢阅读,看张图片轻松一下
唐伯虎点秋香


动手,你才能学会编程
分享,你才能学得透彻

您的支持将鼓励我继续创作!