爬虫 2
爬虫 2
爬虫就像一个寄生虫,但它不是病毒,它可以成为我们利用的一个工具。爬虫也并不是一种很高大上的项目,每个对信息获取有需求的人都应该去了解一下网络爬虫,可以通过爬虫在法律允许的范围内获取很多必要的信息以及对信息进行分析处理。爬虫会不会很难呢?莫道南山迟,请君步行缓。一点点python基础就可以迅速入门爬虫。
正则表达式
正则表达式就是描述字符串排列的一套匹配规则。例如:可以通过正则表达式来匹配一个页面所有的电子邮箱,然后再提取出所有符合正则表达式匹配规则的所有电子邮箱。
正则表达式是所有语言通用的匹配规则。
python使用正则表达式需要导入re模块。
基础知识
-
原子:正则表达式中最基本的组成单位,正则表达式最少包含一个原子
(1) 普通字符作为原子
import re if __name__ == '__main__': pattern = "baidu" string = "http://www.baidu.com" result = re.search(pattern, string) print(result)
(2) 非打印字符作为原子
此处的非打印字符是指:在字符串中用于格式控制的符号,如:换行符、制表符等
import re if __name__ == '__main__': pattern = '\n' string = '''http//www.baidu.com https://cn.bing.com/''' result=re.search(pattern, string) print(result)
(3) 通配字符作为原子
通配字符:一个原子可以匹配一类字符。
符号 | 含义 |
---|---|
\w | 匹配任意一一个字母、数字或下划线 |
\W | 匹配除字母、数字和下划线以外的任意一个字符 |
\d | 匹配任意一个十进制数 |
\D | 匹配除十进制数以外的任意一个其他字符 |
\s | 匹配任意-一个空白字符 |
\S | 匹配除空白字符以外的任意一个其他字符 |
import re
if __name__ == '__main__':
pattern = '\waid\w'
string = '''http//www.baidu.com
https://cn.bing.com/'''
result=re.search(pattern, string)
print(result)
(4) 原子表
原子表可以定义一组低位相等的原子,匹配时可以对表中任意一个原子进行匹配。
import re
if __name__ == '__main__':
pattern = '\waid[abcu]'
string = 'http//www.baidu.comhttps://cn.bing.com/'
result = re.search(pattern, string)
print(result)
- 元字符
元字符就是正则表达式中具有一些特殊含义的字符,用于设计更为复杂的正则表达式。如:重复n次前面的字符等。
符号 | 含义 |
---|---|
. | 匹配除换行符以外的任意字符 |
^ | 匹配字符串的开始位置 |
$ | 匹配字符串的结束位置 |
* | 匹配0次、1次或多次前面的原子 |
? | 匹配0次或1次前面的原子 |
+ | 匹配1次或多次前面的原子 |
{n} | 前面的原子恰好出现n次 |
{n,} | 前面的原子至少出现n次 |
{n, m} | 前面的原子至少出现n次,至多出现m次 |
| | 模式选择符 |
() | 模式单元符 |
以上是常用的元字符。
元字符也可以分为四种类型:
(1) 任意匹配元字符
使用’.'可以代替匹配任意除换行符以外的字符,可以叠加多个使用,‘…'可以代表任意匹配5个字符。
(2) 边界限制元字符
‘^’:限制匹配字符串的开始;’$’:限制匹配字符串的结尾。
import re
if __name__ == '__main__':
import re
pattern1 = "^abd"
pattern2 = "^abc"
pattern3 = "py$"
pattern4 = "ay$"
string = "abcdfphp345pythony_py"
result1 = re.search(pattern1, string)
result2 = re.search(pattern2, string)
result3 = re.search(pattern3, string)
result4 = re.search(pattern4, string)
print(result1)
print(result2)
print(result3)
print(result4)
(3) 限定符
限定符包括:*、?、+、{n}、{n,}、{n,m}
其道理很好理解,代码展示与下面的合并进行。
(4) 模式选择符
可以设置多个模式,匹配的时候可以从其中的任意一个模式进行匹配,即存在模式匹配内容的内容项就可以进行匹配。
(5) 模式单元符
模式单元符"()"可以把一些原子组合成一个大原子来使用,小括号括起来的部分会被视作一个整体。
import re
if __name__ == '__main__':
pattern1 = "(cd){1,}"
pattern2 = "ba{1,}"
string = "abcdcdcdcdfbaaaaidu"
result1 = re.search(pattern1, string)
result2 = re.search(pattern2, string)
print(result1)
print(result2)
通过这可以看到(cd)已经把这两个原子合并一起了,ba{1,}也成功匹配了重复a多次的aaaa。
- 模式修正
如名字而言,是一种对原来正则表达式的修正。可以在不改变正则表达式的情况下,通过修正符改变正则表达式的搜索匹配细则(增加参数),从而调整一些匹配结果。
符号 | 含义 |
---|---|
I | 匹配时忽略大小写 |
M | 多行匹配 |
L | 做本地化识别匹配 |
U | 根据Unicode字符及解析字符 |
S | 让.匹配包括换行符,即用了该模式修正后,“.”匹配就可以匹配任意的字符了 |
可以看到这些符号都是大写的字幕。并且不对原正则表达式的意向进行大面积修改。
import re
if __name__ == '__main__':
pattern1 = "(cd){1,}"
pattern2 = "Ba{1,}"
string = "abcdcdcdcdfbaaaaidu"
result1 = re.search(pattern1, string)
result2 = re.search(pattern2, string)
result3 = re.search(pattern2, string, re.I)
print(result1)
print(result2)
print(result3)
result2因为大小写原因不能正常匹配,但是result3通过其匹配方法的修改成功匹配。
4. 贪婪模式与懒惰模式
对于一些正则表达式需要用上限定符,它会对一段内容进行匹配,但是问题来了。我有一段字符abaaaab,那么前面两个字符ab符合构造a.*b,但是整段内容也符合a. *b 。那么最后是那种结果呢?在这我们需要了解贪婪和懒惰两种模式。
贪婪模式就是对搜寻对象进行不断的搜索,哪怕找到符合的匹配字符串,也还会一直到找到结尾字符还没有搜索到为止。
懒惰模式就是就近选择,从头开始搜索找到匹配的字段就停止搜索。
两者各有优点确定,往往需要根据需要进行选择。
import re
if __name__ == '__main__':
import re
pattern1 = "p.*y" # 贪婪模式
pattern2 = "p.*?y" # 懶惰模式
string = "abc1111dfphp1111345pythony_PY"
result1 = re.search(pattern1, string)
result2 = re.search(pattern2, string)
print(result1)
print(result2)
平常构造的正则表达式匹配过程中是默认贪婪模式,如果想修改成懒惰算法
只需要在".*结尾部分中 * 的后面加上?即可。所以上面所说的内容(search方法),是默认贪婪算法,即最后结果应该是整段文字内容。
正则表达式常见函数
主要介绍五个函数:
- re.search(pattern, string[, flag])对整个输入的字符串进行扫描处理, 《贪婪算法
- re.match(pattern, string[, flag])从源字符串的起始位置匹配,《懒惰算法
- re.compile(pattern[,flags]) 该函数为包含的正则表达式字符串创建模式对象,可以更加有效的实现匹配。在每次一进行根据正则表达式进行匹配搜索的时候都会转化成正则化表达式对象,如果已经完成了这部编译,那么可以直接调用该对象的search或者之类的方法完成匹配搜索。
- pattern.findall(strings[,flags])
这个函数可以输出所有能和正则表达式匹配的结果。但是用法和上述两个略有不同。
在使用前首先需要进行一个预编译。为什么要进行预编译呢?上面谈到了一个问题,每次搜索都需要进行一个转化的过程,findall是搜所所有匹配的结果,每次重新的搜索都需要重新转换会需要很多时间,如果之前提取编译在用转化后对象的方法可以省去很多时间。
findall中的strings是需要搜寻的字符串,pattern是转化后的对象。flags是可选的模式修正。
import re
if __name__ == '__main__':
string = ".baidu.http://www.baidu.comabaiducdabcghjk"
pattern = ".baidu*"
# search
result = re.search(pattern, string)
# match
result1 = re.match(pattern, string)
# 全局匹配函数
pattern = re.compile(".baidu.") # 预编译
result2 = pattern.findall(string) # 找出符合模式的所有结果
print(result)
print(result1)
print(result2)
- re.sub(pattern, rep, string[,max])
这个函数可以实现根据正则表达式来替换某些字符串的功能。rep是用来代替符合正则表达式的内容,max是可以选择最多替换的次数,如果不选,默认全部代替。
import re
if __name__ == '__main__':
string = ".baidu.http://www.baidu.comabaiducdabcghjk"
pattern = ".baidu."
result1 = re.sub(pattern, "google", string)
print(string)
print(result1)
以上就是正则表达式的所有内容。已经可以完成所有正则式的构造。接下来的就是多多练习。
小练习
1.匹配一个10位数字长度的QQ邮箱格式的正则表达式
\d{10}@qq.com2.匹配一个com或者是cn结尾的url
[a-zA-Z]+://[^\s]*[.com|.cn]
3.匹配一个**.txt文件格式的正则表达式
4.匹配一个“商品名:价格¥”的正则表达式
对于自己的构造是否正确直接复制一段含有检测对象的strings,使用上述方法search一下,输出预期结果则构造正确。
平时使用的时候可以用在线网站检测一下自己构造的正则表达式是否正确,或者用响应工具生成。
Cookie
cookie简单的来讲我们在一个特定网页保存登录密码,或者保持登录状态的一个东西。由于http是静态的,你可能本来在上一个页面是登录过了,但是用爬虫爬取下一个页面的时候这些信息是会丢失的,需要cookie来自动实现对原来保存信息的提交。才可以像我们正常浏览网页一样,不用没点开一个页面都需要登录个人信息。
内容很少,但是结合一个小示例,来熟悉复习一下上一篇文章的内容。为接下来的实战作基础铺垫。
这里需要导入处理Cookie的模块CookieJar。然后通过导入的这个模块来创建Cookiejar的对象,在使用HTTPCookieProcessor创建cookie处理器,并以此为其参数构建opener参数。创建全局默认的opener对象,使得openurl可以默认使用设置Cookie。
import urllib.request
import urllib.parse
import http.cookiejar
if __name__ == '__main__':
url = "http://bbs.chinaunix.net/member.php?mod=logging&action=login&loginsubmit"
postdata = urllib.parse.urlencode({
"usernam" : "Fasthand",
"password" : "Viking123"
}).encode('utf-8')
req = urllib.request.Request(url, postdata)
req.add_header("User-Agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Mobile Safari/537.36")
cjar = http.cookiejar.CookieJar()
#上面创建一个名称为cjar的CookeJar对象,使用的方法为http.cookiejar.CookieJar()
processor = urllib.request.HTTPCookieProcessor(cjar)
#上面通过HTTPCookieProcessor创建cookie处理器
opener = urllib.request.build_opener(processor)
#通过以Cookie处理器为参数构造opener对象
urllib.request.install_opener(opener)
#将opener对象设置安装为全局
file = opener.open(req)
#以上打开设置的URL,并且其中已经添加了报头信息
data = file.read()
file = open("D:\\programfile\\python3\\inf\\crawler.html", "wb")
file.write(data)
file.close()
url2 = "http://bbs.chinaunix.net/"
data2 = urllib.request.urlopen(url2).read()
fhandle1 = open("D:\\programfile\\python3\\inf\\crawler2.html", "wb")
fhandle1.write(data2)
fhandle1.close()
以上就是简单的静态页面爬虫需要的知识,后续还有相关于Fidder、beautiful soup库、Scrapy框架的相关内容。
目前两篇文章内容以及可以完成日常中需要爬取的相关信息了,制作微型爬虫就是这么简单~
上一篇: PYTHON 爬虫 必应词典翻译爬取