什么是爬虫?
爬虫指的是:一段自动抓取互联网信息的程序,从互联网上抓取对于我们有价值的信息。
(注意:对涉及隐私信息进行爬取是违法的哦!)
Python 爬虫架构主要由五个部分组成
分别是调度器、URL管理器、网页下载器、网页解析器、应用程序(爬取的有价值数据)。
调度器:相当于一台电脑的CPU,主要负责调度URL管理器、下载器、解析器之间的协调工作。
URL管理器:包括待爬取的URL地址和已爬取的URL地址,防止重复抓取URL和循环抓取URL,实现URL管理器主要用三种方式,通过内存、数据库、缓存数据库来实现。
网页下载器:通过传入一个URL地址来下载网页,将网页转换成一个字符串,网页下载器有urllib2(Python官方基础模块)包括需要登录、代理、和cookie,requests(第三方包) 网页解析器:将一个网页字符串进行解析,可以按照我们的要求来提取出我们有用的信息,也可以根据DOM树的解析方式来解析。
网页解析器有正则表达式(直观,将网页转成字符串通过模糊匹配的方式来提取有价值的信息,当文档比较复杂的时候,该方法提取数据的时候就会非常的困难)、html.parser(Python自带的)、beautifulsoup(第三方插件,可以使用Python自带的html.parser进行解析,也可以使用lxml进行解析,相对于其他几种来说要强大一些)、lxml(第三方插件,可以解析 xml 和 HTML),html.parser 和 beautifulsoup 以及 lxml 都是以 DOM 树的方式进行解析的。
应用程序:就是从网页中提取的有用数据组成的一个应用。
了解了爬虫我们就进行一个简单的爬虫程序吧!
# 导入功能库
import urllib2
# 调用urllib2 中的urlopen方法
response = urllib2.urlopen("http://www.baidu.com")
# 读取网页内容
print response.read()
首先我们调用的是 urllib2 库里面的 urlopen 方法,传入一个 URL,这个网址是百度首页,协议是 HTTP 协议,当然你也可以把 HTTP 换做 FTP,FILE,HTTPS 等等,只是代表了一种访问控制协议,urlopen 一般接受三个参数,它的参数如下:urlopen(url, data, timeout) 第一个参数 url 即为 URL,第二个参数 data 是访问 URL 时要传送的数据,第三个 timeout 是设置超时时间。 第二三个参数是可以不传送的,data 默认为空 None,timeout 默认为 socket._GLOBAL_DEFAULT_TIMEOUT 第一个参数 URL 是必须要传送的,在这个例子里面我们传送了百度的 URL,执行 urlopen 方法之后,返回一个 response 对象,返回信息便保存在这里面。
构造Request
其实上面的 urlopen 参数可以传入一个 request 请求,它其实就是一个 Request 类的实例,构造时需要传入 Url,Data 等等的内容。比如上面的两行代码,我们可以这么改写
import urllib2
# 构造一个请求
request = urllib2.Request("http://www.baidu.com")
# 传入请求,打开网页
response = urllib2.urlopen(request)
# 读取网页内容
print response.read()
Post方式
我们引入了 urllib 库,现在我们模拟登陆百度,当然上述代码可能登陆不进去,因为百度有个流水号的字段,没有设置全,比较复杂在这里就不写上去了,在此只是说明登录的原理。一般的登录网站一般是这种写法。 我们需要定义一个字典,名字为 values,参数我设置了 username 和 password,下面利用 urllib 的 urlencode 方法将字典编码,命名为 data,构建 request 时传入两个参数,url 和 data,运行程序,返回的便是 POST 后呈现的页面内容。
注意上面字典的定义方式还有一种,下面的写法是等价的
import urllib
from urllib import request
# 定义参数(字典类型)
values = {"username":"159753456","password":"88888888"}
# 参数编码
data = urllib.parse.urlencode(values).encode(encoding="utf-8")
# 定义url
url ="http://passport.baidu.com/v2/?login"
# 构造request请求
req= request.Request(url,data=data)
# 打开网页
resp=request.urlopen(req)
# 打印网页内容
print(resp.read())
爬虫程序添加data、header,然后post请求
#导入功能库库名
urllib urllib2
import urllib
import urllib2
#填写地址url
url = 'http://www.server.com/login'
#设置Headers 的参数
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
#设置data 参数是访问URL时要传送的数据
values = {'username' : 'xxxxxxxxx', 'password' : 'xxxxxxxxxxx' }
#设置Headers 的属性
headers = { 'User-Agent' : user_agent }
#对data数据进行编码
data = urllib.urlencode(values)
#进行请求
request = urllib2.Request(url, data, headers)
#进行访问
response = urllib2.urlopen(request)
#返回获取到的网页内容
page = response.read()
爬虫程序添加cookie
from urllib import request
from http import cookiejar
# 定义cookie,用来存cookie
cookie = cookiejar.CookieJar()
# 定义一个cookie处理器,将cookie传进去
handler = request.HTTPCookieProcessor(cookie)
# 定义下载器,将cookie处理器传进去
opener = request.build_opener(handler)
# 用下载器下载页面
resp = opener.open("http://www.baidu.com")
# cookie的数据类型=字典=多个键值对
for item in cookie:
print("key="+item.name)
print("value="+item.value)
常见的正则表达式
字符 | 描述 |
---|---|
\ | 将下一个字符标记为一个特殊字符(File Format Escape,清单见本表)、或一个原义字符(Identity Escape,有^$()*+?.[{|共计12个)、或一个向后引用(backreferences)、或一个八进制转义符。例如,“n”匹配字符“n”。“\n”匹配一个换行符。序列“\\”匹配“\”而“\(”则匹配“(”。 |
^ | 匹配输入字符串的开始位置 |
$ | 匹配输入字符串的结束位置 |
* | 匹配前面的子表达式零次或多次。例如,zo*能匹配“z”、“zo”以及“zoo”。*等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。 |
? | 匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“does”中的“do”和“does”。?等价于{0,1}。 |
{n} | n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。 |
{n,} | n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。 |
{n,m} | m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。 |
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
# 导入re
import re
# 匹配所有数字,字母
rexg = re.compile(r'\d*\w*')
res = re.search(rexg, 'ddddd22dddd')
print(res)
# 匹配数字+字母的特定组合
rexg2 = re.compile(r'\d+\w*')
res2 = re.search(rexg2, 'ppppp5555ddddd')
print(res2)
rexg3 = re.compile(r'\d?')
res3 = re.search(rexg3, '9999ddddd')
print(res3)
# 定义正则规则,手机号
rexg4 = re.compile(r'1\d{10}')
res4 = re.search(rexg4, '888884415888888888888')
print(res4)
# 定义正则规则,邮箱
rexg5 = re.compile(r'\d{5,12}@\w{2}\.\w{3}')
res5 = re.search(rexg5, 'asfwqqraf789465798@qq.comasda')
print(res5)
rexg6 = re.compile(r'\d{5,10}?')
res6 = re.search(rexg6, '456789123184135')
print(res6)
# 边界匹配
rexg7 = re.compile(r'^abc')
res7 = re.search(rexg7,'abcqooisf')
print(res7)
# 任意
rexg8 = re.compile(r'1\d{10}|\d{5,12}@qq\.com')
# 优先匹配左边
res8 = re.search(rexg8,'ddafdfsadf1116554815184asdfsafa54565465@qq.com')
print(res8)
# 分组
rexg9 = re.compile(r'(abc){3}')
res9 = re.search(rexg9,'999999999abcabcabcjyyyyyyy')
print(res9)
# 分组+别名
rexg10 = re.compile(r'(?P<tt>abc)88(?P=tt)')
res10 = re.search(rexg10,'999999999abc88abcabcjyyyyyyy')
print(res10)
# 分组+编号
rexg11 = re.compile(r'(\d{5})uu\1')
res11 = re.search(rexg11,'12312uu12312132')
print(res11)