re模块的使用完全是为了方便各种规律性没有那么强的文档的提取,尤其是对于爬取的html数据。当然,对于爬取的数据不是完全用re,还是根据根据爬取到的html格式决定,比如当爬取的数据是表格数据时,直接使用pd.read_html()可以方便高效的提取相应的数据;当爬取的数据是json格式文件时,直接使用response.json(),然后就利用字典的get方法,获取相应的参数;只有当html文件没有固定的格式时,采用re去自建规则去提取相应的数据。
下面就上面提到的各种方式进行简单的测试:
1、表格数据
网址:“http://vip.stock.finance.sina.com.cn/q/go.php/vComStockHold/kind/jjzc/index.phtml”
直接使用pd.read_html()获取
data = pd.read_html("http://vip.stock.finance.sina.com.cn/q/go.php/vComStockHold/kind/jjzc/index.phtml")
data[0]
# 至于为啥用切片,是因为该页面有很多个Tables数据,所有会返回一个列表,而需要的数据只是第一个
结果展示
2、json数据
网址:“https://search.51job.com/list/090200,000000,0000,00,9,99,亚马逊运营,2,1.html?lang=c&postchannel=0000&workyear=99&cotype=99°reefrom=99&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare=”
直接使用response.json()
res = requests.get(url=urls, headers=headers).json()
items_list = res.get('engine_search_result')
if items_list:
vau = []
for i in items_list:
item = {}
item['keyword'] = keyword
item['job_name'] = i.get('job_name')
item['company_name'] = i.get('company_name')
结果展示
3、无特殊格式的数据
这种数据没得特殊格式,想要获取相应的数据,就需要自己去建立规则,提取数据,这时候就用到了re模块。
网址:“https://jobs.51job.com/chengdu/132231033.html?s=sou_sou_soulb&t=0=”
需求:想要获取岗位职责和任职要求数据
就需要用re建立规则
首先介绍re模块
re模块自带6种方法,具体如下:
-
re.compile: 编译一个正则表达式模式(pattern),也就是建一个规则
-
re.match: 从头开始匹配, 使用group()方法可以获取单个匹配值
-
re.search: 用包含方式匹配,使用group()方法可以获取单个匹配值
-
re.findall: 用包含方式匹配,把所有匹配到的字符放到以列表中的元素返回多个匹配值
-
re.sub: 匹配字符并替换
-
re.split: 以匹配到的字符当做列表分隔符,返回列表
了解了主要的函数,那么就先从建立规则开始:
一、建立规则的表达式
re模块提供的匹配表达式众多,下面就写一些重要且常用的。
模式 | 描述 | 示例 |
---|---|---|
. | 匹配任意字符,除了换行符。 | re.compile(".") |
* | 贪婪匹配,与.连用,匹配0个或多个的表达式。 | re.compile(".*") |
+ | 贪婪匹配,与.连用,匹配1个或多个的表达式。 | re.compile(".+") |
? | 非贪婪匹配,与贪婪模式连用,按要求截断贪婪模式 | re.compile(".*?") / re.compile(".+?") |
{n} | 精确匹配 n 个字符,与.连用或者与具体字符 | re.compile(".{5}") / re.compile(“a{5}”) |
{ n, m} | 匹配 n 到 m 个由前面的正则表达式定义的片段,贪婪方式 | re.compile(“a{2,5}”) 既可以匹配2个a,也可以3、4、5个 |
() | 匹配括号内的表达式,也表示一个组,多与单个字符匹配的方法连用,如search | re.search(r"(.0{3})",res.text).group(1) |
一些专用的匹配表达式
模式 | 描述 |
---|---|
\w / \W | 匹配字母数字及下划线 / 匹配非字母数字及下划线 |
\s / \S | 匹配任意空白字符,除了换行符,等价于 [\t\n\r\f]。 / 匹配任意非空字符 |
\d /\D | 匹配任意数字,等价于 [0-9] / 匹配非数字 |
\A / \Z / \z | 匹配字符串开始 / 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 /匹配字符串结束 |
[\u4e00-\u9fa5] | 匹配中文字符 |
二、建立规则
使用函数:re.compile(pattern, flags=0)
参数详解:
pattern:表达式
flags:可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
- re.I 忽略大小写
- re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
- re.M 多行模式
- re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
- re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
- re.X 为了增加可读性,忽略空格和 # 后面的注释
注意:以上flag可多个一起用,例如同时使用re.I | re.M。
规则建立好了,就开始匹配
re包含三个匹配函数
re.match:从头匹配字符串,若存在多个,返回第一个
re.search:从任意位置开始匹配,若存在多个,返回第一个
另外,以上两个函数返回值可以使用.group()提取匹配字符串,当然这就必须在表达式中使用()
>>> string3 = "Elephants are bigger than rats";
>>> match3 = re.search( r'(.*) are (.*?) .*', string3, re.M|re.I)
>>> print(match3.group())
Elephants are bigger than rats
>>> print(match3.group(1)) # 这里的group(1) 就是第一个括号内的内容
Elephants
>>> print(macth3.group(2)) # 这里的group(2) 就是第二个括号内的内容
bigger
re.findall:用于匹配长字符串中所有符合条件的字符,输出结果是一个列表
pattern = re.compile(r"\d{8}")
a = re.findall(pattern,res.text)
a
>>>
['13223103',
'13223103',
'13223103',
'13223103',
'13223103',
'20180319',
'16224299',
'79786637',
'20210511']
其他两个函数方法re.sub和re.split实际用途不怎么多,这里就不多介绍了
示例练习
针对第三点,无特殊格式的数据,做一个小示例
网址:“https://jobs.51job.com/chengdu/132231033.html?s=sou_sou_soulb&t=0=”
需求:想要获取岗位职责和任职要求数据
通过观察多个html文件,发现需要的信息主要是在 bmsg job_msg inbox 节点后,但是这个节点却有很多的其他的东西,我这里直接用sub函数把网页的标志都替换掉了,至于为啥引入b变量,直接替换一直替换不掉,有知道的大神可以指教。对了," .* " 贪婪模式截断点是换行符
pattern = re.compile(r"bmsg job_msg inbox\">\r\n .*")
a = re.findall(pattern,res.text)
b = re.findall("[\u4e00-\u9fa5]|\w|.",a[0])
b = "".join(b)
for i in [ "<br>", "</span>", "stylefont-familyArialfont-size","pxbackground-colorFFFFFF",
"<li>","</li>","</div>","<div>","<p>","</p>","\r","bmsg job_msg inbox\">","ul","<b>",
"</b>","</ol>","<ol>","<span>","</br>"]:
b = re.sub(i," ",b)
b.strip()
提取之前
提取之后