初学者爬虫运行基础:正则表达式
Posted 贝壳索思科技
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初学者爬虫运行基础:正则表达式相关的知识,希望对你有一定的参考价值。
爬虫运行基础:正则表达式
首先我先介绍一下什么是正则表达式(regexp),在这里本文中我使用javascript和python语言为范例,其他语言请自行转换。
正则表达式是一个非常强大的工具可以匹配某个模式或者形态的字符串:
var regex = /ab+c/;
regex = /^[a-zA-Z]+[0-9]*\W?_$/gi;
以上就是两个正则表达式语句。别一头雾水,作用是啥,等我一一道来。
我先讲两个小例子:
`/abc/`
可以匹配`"Hi, do you know your abc's?" `其中的abc
不能匹配`Grab crab`因为没有连续的abc出现
&
`/ab*c/`
一个a后面匹配了一定数量个b,可以是零个,最后还得带c
"cbbabbbbcdebc"
就可以匹配上其中的abbbbc
那么‘*’、‘?’、‘.‘等这些符号究竟代表什么意思呢? 简单说一下
‘\’ 一般代表转义字符等,具体用法根据情况不同而不同。
‘^’ 匹配的开始,比如/^A/就不会匹配 字符串’a An'中的 A,但是可以匹配上'An E'中的A,大概逻辑就是这样,认为它打头阵就行。
‘*’匹配前一个表达式0次或者多次。
‘.’匹配出了换行符之外任何单个字符。
‘?’这个是匹配前面一个表达式0次或者一次。
不理解以上的表达也没关系,看两个实例你就能明白,然后就可以优雅的使用正则表达式了。
正则表达式一般是逐步写出来的,我们新手一般不能直接根据条件一步写出目的表达式。
在freecodecamp中有个这样的题目:
Q.将字符串转换为 spinal case。Spinal case 是 all-lowercase-words-joined-by-dashes 这种形式的,也就是以连字符连接所有小写单词。
01
现在我们来翻译一下。
题目的意思是要把"University of Science Technology Beijing" 这样的字符转化成 "university-of-science-technology-beijing"这样的格式;
"Teletubbies say Eh-oh" 这样的字符转化成 "teletubbies-say-eh-oh";
也就是说必须把所有字母都变成小写并且在原来有意分割的位置打上一个连词符号。这通通可以用正则表达式来完成
function spinalCase(str) {//括号里的参数就是待转化的字符
str = str.replace(/\s/g,"-")
//把出现的空白字符转化成"-"
str = str.replace(/([a-z])([A-Z])/g,'$1-$2')
//将遇到的小写和大写链接处中间加一个‘-’,比如aB替换为a-B
str = str.toLowerCase();
//这个是转化成小写,和正则无关
看到正则表达式的强大了么? 你想匹配什么都可以做到,比如老美子的号码
02
还是一道来自freecodecamp中的题目:
555-555-5555
(555)555-5555
(555) 555-5555
555 555 5555
5555555555
1 555 555 5555
02
区号是必须有的. 如果字符串中给出了国家代码, 你必须验证其是 1.
如果号码有效就返回 true ; 否则返回 false.
分析题目:
1.第一部分是美国的国家代码1,有的人输入有的人不输。我们可以认为他匹配一次或者零次使用’?‘即可完成
2.第二部分是区号长度是3
美国的国家代码是1,有时候写有时候不写:
^1:也许可以完成任务,他可以匹配以1开头的表达式 但是有时候1不存在啊。
2
?可以表示匹配1次或者0次
^1?:再考虑一下1有时候后面还带一个空格
^1? ?:给空格也加一个?表示空格可能有也可能没有
3
后面就会出现三个数字,三个数字,四个数字,中间夹杂(空格)或者-
d{3}代表三个数字
括号和没有括号两种情况用|放在一起表示或
/^1? ?\(\(d{3}\)|\d{3})/
后面的七个数字之间有可能是空格也有可能是连词符号’-‘,所以我们使用[ |-]来表示空格或者连词符号存在其中一个
最终为/^1? ?(\(\d{3}\)|\d{3})[ |-]?\d{3}[ |-]?\d{4}/
4
但是还是无法匹配少部分情况
("27576227382") 应该返回 false.
("(275)76227382") 应该返回 false.
错误原因估计是直接把括号打到最顶上无法识别,没有1而且位数也不对,如果有其他想法也可以和我讨论
我们在最后加一个$(表示匹配结束)控制一下位数然后就可以成功
/^1? ?(\(\d{3}\)|\d{3})[ |-]?\d{3}[ |-]?\d{4}/$
那么问题来了,我要的爬虫哪去了?
我看到一个网站
里面有3000多个页面分别放了一些非常文艺的作品。
我就用他来讲讲我的第一个爬虫吧
网页长啥样和我没关系,我们先爬下来看看到底长啥样
在Python命令行或者终端中运行python
我们先import requests假如no model的话先exit()回来pip或者pip3 安装一个模块
pip3 install requests
好了然后运行正常就是这样
>>> content =
requests.get('http://wufazhuce.com/article/9')
使用requests模块中的get操作对目标网页进行获取 然后我们把它print()出来看看他到底是何方神圣
这就是我们把别人html源码给爬下来的结果
接下来我们来寻找一下我们要的部分
上面的字符内容是这样的:
<div class="articulo-contenido">
【蔡康永的躲避诗】<br><br>终于又拖到天黑了<br><br>太阳它蹲在湿漉漉的路边抽着烟<br><br>想着也许明天起不要再去上班了<br><br>
【蔡康永的躲避诗】<br> <br>坚决的说从此不要再见到你<br><br>然后当晚就梦见你啦<br><br>真是一点尊严也没有<br><br>
【蔡康永的躲避诗】<br><br>听说世界很大啊<br><br>就到街头张望了好几分钟<br><br>结果也并没有什么地方可以去<br><br>
【蔡康永的躲避诗】<br><br>要分手就分吧<br><br>不用说什么你配不上我这种话<br><br>我们又不是手机和充电器<br><br>
【蔡康永的躲避诗】<br><br>很挤吗?<br><br>那么让我把我的座位让出来吧<br><br>虽然我知道最后你也不会满意的
</div>
<p class="articulo-editor">
(责任编辑:薛诗汉)
</p>
<p class="articulo-compartir">
在html中对应代码是一对换行符所以才会那么乱(弱弱地:当然贴心的小编已经把代码整理过了)
我们先把我们需要的部分给匹配了观察到主要内容顶上有一个<div class="articulo-contenido">结束处有<p class="articulo-compartir">
那么整个网页其他地方我们就不要啦,
这时候我们在python中引入正则表达式模块工具
>>>import re
还得顺带说一下python中的re包的简单用法:
findall的用法
d = re.findall(’/regexp/‘,s)
从字符串中匹配所有的内容返回给d
search的用法
f = re.search('xxx(.?)xxx(.?)***’,s2).group(n)
n可以等于1或者2 因为里面只有两个括号,一个括号对应一个group
sub的用法
s = ‘123abafasdfas123’ out =
re.sub(‘123(.*?)123’,‘123789123’,s)
他会替换内容为设置内容
知道以上这些我们已经可以完美应对普通大多数情况了
>>> article = re.findall('<div class="articulo-contenido">(.*?)<p class="articulo-compartir">',content.text,re.S)
//注一:re.S可以让.匹配不同行的内容
//注二:(.*?)这个值的可以匹配任何字符有多少匹配多少
那匹配之后我们再把它print出来看看是雄是雌
现在已经简化多了但是还有一些非常繁杂的字符类似于","等任何或者其他html实体(想了解请自行百度) 你只要用sub操作替换一下就可以了
f = open('./content/text.txt','wb')//创建一个text文本文件,并设置为写入状态
for i in article:
i = re.sub('<br>','\n',i)
i = i.encode(encoding = 'utf-8')
f.write(i)
我使用了本来的换行,并且把编码改为utf-8最后用python文件写入操作把内容写进test.txt中就完成了。
接下来就是我要实现自动翻页把这个网站所有的文章都爬下来请看我的代码
import requests
import re
url = 'http://wufazhuce.com/article/'
for i in range(10,3500)://用for循环实现翻页
html = requests.get(url+'{0}'.format(i))
//我把获取url+i的内容
title = re.findall('<title>(.*?)</title>',html.text,re.S)
//获取标题
article = re.findall('<div class="articulo-contenido">(.*?)<p class="articulo-compartir">',html.text,re.S)
//获取文章内容
f = open('./content/text'+str(i)+'.txt','wb')
//创建文件
for i in title:
i = i.encode(encoding = 'utf-8')
f.write(i)
for i in article:
i = re.sub('<br>','\n',i)
i = re.sub('<.*?>','',i)
i = re.sub('<strong>','',i)
i = re.sub('&rdquo','',i)
i = re.sub('&ldquo','“',i)
i = re.sub('&hellip','……',i)
i = re.sub('×','',i)
//以上都是一些html实体或者代码我把他们转化成了对应的内容,如果有什么更好的方法可以实现这个操作也来和我讨论吧。
i = i.encode(encoding = 'utf-8')
f.write(i)
最后 $ python3 spider.py 运行他就乖乖把所有这个网站上的所有内容趴下来一个个的躺在文件夹里
这只是一个简单的没有任何伪装的爬虫,稍微有反爬虫机制的网站都不会让这种简单的爬虫进入。这也只是单线程爬虫。
正则表达式表达式是一条非常深的路。
爬虫也是一门很深的学问。
文案:赵文杰
排版:范雨晴
以上是关于初学者爬虫运行基础:正则表达式的主要内容,如果未能解决你的问题,请参考以下文章
正则表达式 与 XPath 语法领域细解,初学阶段的你,该怎么学?
正则表达式 与 XPath 语法领域细解,初学阶段的你,该怎么学?