目录
1. 爬虫概念
- 爬虫:是一段自动抓取网页信息的程序
- 爬虫原理:模拟浏览器打开网页,获取网页中的数据
2. 网页基础
首先可以用Chrome浏览器打开百度首页,查看源代码(Chrome浏览器需要安装谷歌访问助手,不然无法使用,安装详情)。
右键点击"检查"即可打开网页控制台。我们主要关注Elements和Network两个选项卡,Elements里面是当前网页的源码。
- HTML:超文本标记语言是用来描述网页的一种语言。网页包括文字、按钮、图片和视频等各种复杂的元素,不同类型的元素通过不同类型的标签来表示,他们之间的布局又通过布局标签div嵌套组合而成,各种标签通过不同的排列和嵌套形成了网页的框架。
- CSS:层叠样式表。"层叠"是指当在HTML中引用了数个样式文件,并且样式发生冲突时,浏览器能依据层叠顺序处理。"样式"指网页中文字大小、颜色、元素间距、排列等格式。
- JavaScript:一种脚本语言。可以实现实时、动态、交互的页面功能。
- 总结:HTML定义了网页的内容和结构,CSS描述了网页的布局,JavaScript定义了网页的行为。
HTTP基本原理
URL(Uniform Resource Locator, 统一资源定位符):定义互联网上的唯一资源,一张图片、一个文件、一段视频都可以用URL编码,如:https://www.baidu.com/s?wd=爬虫
一个完整的URL 包括协议部分、网址、文件地址部分。协议部分以//为分隔符,在Internet 中有多种协议:
- http —— Hyper Text Transfer Protocol(超文本传输协议)
- https—— Hyper Text Transfer Protocol over Secure Socket Layer安全套接字层超文本传输协议(http的安全版)
- ftp —— File Transfer Protocol(文件传输协议)
在爬虫中,抓取的页面通常采用http或https协议。
HTTP请求过程
- 请求(Request):用户将本机信息通过浏览器发送给服务器
- 响应(Response):服务器接收请求,分析用户发来的请求信息,然后返回数据(返回的数据中可能包含其他链接,如图片,js,css等),浏览器接收Response后解析其内容再显示给用户
爬虫程序模拟浏览器发送请求,然后在接收Response后,提取其中的有用数据。
请求
- 请求方法(Request Method)
GET:在浏览器中直接输入URL回车
POST:多在表单提交时发起
- 请求网址(Request URL)
- 请求头(Request Headers):Cookie、Referer、User-Agent等
- 请求体(Request Body)
GET请求:请求体没有内容(请求参数放在URL后面,直接能看到,如https://www.baidu.com/s?wd=爬虫)
POST请求:请求内容时格式文本(format data),如登陆窗口、文件上传等信息。
响应
- 响应状态码(Response Status Code)
200:代表服务器正常响应
404:代表页面未找到
500:代表服务器内部发生错误
- 响应头(Response Headers):Content-Type、Set-Cookie等
- 响应体(Response Body):
HTML代码、JSON代码、二进制数据。
爬虫分类
- 通用爬虫:爬行对象从一些种子URL 扩充到整个Web,主要为门户站点搜索引擎和大型Web 服务提供商采集数据。
- 聚焦爬虫:选择性地爬行那些与预先定义好的主题相关的页面。
robots协议
Robots协议(Robots Exclusion Protocol):网络爬虫排除标准,也称为爬虫协议、机器人协议。Robots协议是国际互联网界通行的道德规范,不是命令,也不是防火墙,并不能阻挡刻意闯入者。网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
例如:https://www.taobao.com/robots.txt,robots.txt是搜索引擎访问网站时要查看的第一个文件。
- User-Agent:标明针对的客户端类型
- Allow:标明允许爬取的地址
- Disallow:标明不希望爬取的地址
- Sitemap:指导搜索引擎去爬取页面,避免误爬不希望开放的地址。
爬虫流程
3. 爬虫常用库
请求库
- urllib:Python内置的HTTP请求库
- requests:第三方请求库,功能强大 ,不能执行JS代码
- Selenium:驱动浏览器执行JS渲染
解析库
- lxml:解析和生成xml文件
- BeautifulSoup:从HTML或XML文件中提取数据
- PyQuery:相当于jQuery的python实现,可以用于解析HTML网页等。语法和jQuery几乎完全相同
存储库
- pymysql
- pymongo
- redis
其他库
- re(正则表达式库):通用的网页解析库,也可以对存储后的数据进行数据清洗等相关工作。
4. 正则表达式
正则表达式 (Regular Expression):记录文本规则的代码,常用于检索、替换符合某一规则的文本。
问题:想在一段文本中找寻符合要求的字符串。
思路:根据需要将这些符合要求的特定字符及这些特定字符的组合,形成一个“规则字符串”,通过组合的“规则字符串”来对字符串进行过滤,从而匹配出想要的特定字符串。
正则表达式小抄
贪婪与非贪婪模式
贪婪模式,总是尝试匹配尽可能多的字符。
非贪婪模式,也称为“懒惰”模式,总是匹配尽可能少的字符。
编程语言中正则表达式应用
- 反斜杠问题
与大多数编程语言相同,正则表达式里使用”\”作为转义字符,这就可能造成反斜杠困扰。
假如需要匹配文本中的字符”\”,那么使用编程语言表示的正则表达式里将需要4个反斜杠”\\\\”:前两个\\和后两个\\分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。
Python里的原生字符串r很好地解决了这个问题,要匹配字符”\”,正则表达式可以用r”\\”来表示。同样,匹配一个数的”\\d”可以写成r”\d”。
Python正则表达式匹配流程
利用正则表达式爬取信息三步曲
- Step1:先将正则表达式的字符串形式(即规则)编译为正则表达式对象。
prog = re.compile(pattern)
- Step2:然后使用这一对象处理文本并获得匹配对象,如果匹配不成功,就返回none。
result = prog.match(string)
- Step3:输出匹配结果。
print(result)
PS:Step1,2可以合并为一步:
result = re.match(pattern, string)
其中pattern可以是正则表达式的字符串形式,也可以是正则表达式对象。
常用正则表达式举例
- 例1:查找字符串中的数字
string = ‘_234werwrE%58\WeR-wRew'
model1 = r'\d'
print(re.findall(model1,string))
model1 = r'\d+'
print(re.findall(model1,string))
- 例2:查找string中的特殊字符:
model2 = r'[_,$-.%\\]'
print(re.findall(model2,string))
- 例3:查找string中的指定字符串(忽略大小写)
model3 = r"wer|wre"
print(re.findall(model3,string,re.I))
- 例4:查找网页中的特定内容
html='<dd><i class="board-index board-index-1">1</i><a href="/films/1203" ' \
'title="霸王别姬"/> <p class="star">主演:张国荣,张丰毅,巩俐</p></dd>'
model4=r'<dd>.*?board-index.*?>(\d+)</i>.*?title="(.*?)"'
+ '.*?star">(.*?)</p></dd>'
print(re.findall(model4,html) , re.S)
几个好用的正则表达式网站:
- https://regexper.com --可以用图形来表示正则表达式的效果
- https://regexr.com/ ----在线测试工具(英文)支持JavaScript
- http://tool.oschina.net/regex --在线测试工具(中文)
re库
- compile()函数
re.compile(pattern [,flags=0]):编译一个正则表达式模式,返回一个模式对象。flag是匹配模式,取值如下:
- match(),search(),findall()函数
re.match(pattern, string, flags=0)
若string中包含pattern子串,则返回真,否则返回假。注意:只从string的开始位置进行匹配。
re.search(pattern, string, flags=0)
若string中包含pattern子串,则返回Match对象,否则返回None,注意,会扫描整个string查找匹配,并返回第一个成功的匹配。
re.findall(pattern, string, flags=0)
返回string中所有与pattern相匹配的全部字串,返回形式为数组
reg= re.findall(r'[t,w]h', 'https://docs.python.org/whats')
print (reg)
- match()、search()、findall()函数中的方法
- sub(),split()函数
re.sub(pattern, repl, string, count=0, flags=0)
输入一个字符串,然后返回被替换后的字符串。
re.split(pattern, string[, maxsplit])
根据指定子串对string进行分割,结果为列表。
将所有数字替换为空格:
s = ‘54aKS4yrsoiRS4ixSL2g’
content = re . sub(‘\d+’, ’’, s)
用数字进行分隔:
print(re.split('\d+','one1two2three3'))
- 注意事项
- 常用正则表达式
含义 |
正则表达式 |
匹配中文字符 |
[\u4e00-\u9fa5] |
匹配空白行 |
\n\s*\r |
匹配Email地址(无中文) |
[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)* @(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])? |
匹配网址URL |
[a-zA-z]+://[^\s]* |
匹配国内电话号码 |
\d{3}-\d{8}|\d{4}-\{7,8} |
匹配腾讯QQ号 |
[1-9][0-9]{4,} |
匹配中国邮政编码 |
[1-9]\d{5}(?!\d) |
匹配18位身份证号 |
^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$ |
匹配(年-月-日)格式日期(1900-2099年,可匹配闰年) |
((((19|20)\d{2})-(0?(1|[3-9])|1[012])-(0?[1-9]|[12]\d|30)) |(((19|20)\d{2})-(0?[13578]|1[02])-31)|(((19|20)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|((((19|20)([13579][26]|[2468][048] |0[48]))|(2000))-0?2-29))$ |
匹配整数 |
^-?[1-9]\d*$ |
import re
emails = ['[email protected]', '1973536%[email protected]', '[email protected]']
pattern = re.compile(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$')
for email in emails:
if re.match(pattern, email):
print('True')
else:
print('False')