1.爬虫
网络爬虫就是模拟浏览器发送网络请求,接受请求响应,一种按照一定的规则,自动地抓取互联网信息的程序。
当我们在浏览器中输入一个url后按回车会发生什么:
- 查找域名对应的IP地址
- 向IP对应的服务器发送请求
- 服务器响应请求吗,发回网页内容
- 浏览器解析网页内容
经常使用到的库:
1 2 3 4 5 6
| from bs4 import BeautifulSoup import re import urllib.request, urllib.error import xlwt import sqlite3
|
2.抓取
Python学习网络爬虫主要分3个大的版块:抓取,分析,存储;我们来详细说说抓取部分。
(1)基本抓取
抓取大多数都属于get请求,也就是说直接从对方服务器上获取数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Requests: import requests response = requests.get(url) content = requests.get(url).content print "response headers:", response.headers print "content:", content Urllib2: import urllib2 response = urllib2.urlopen(url) content = urllib2.urlopen(url).read() print "response headers:", response.headers print "content:", content Httplib2: import httplib2 http = httplib2.Http() response_headers, content = http.request(url, 'GET') print "response headers:", response_headers print "content:", content
|
此外,对于带有查询字段的url,get请求一般会将来请求的数据附在url之后,以?分割url和传输数据,多个参数用&连接。
举个例子:
- 基础URL:
http://www.example.com/products
- 查询参数:
category
: “books”
sort
: “price_asc”
1
| http://www.example.com/products?category=books&sort=price_asc
|
1 2 3 4 5 6 7 8 9
| data = {'data1':'XXXXX', 'data2':'XXXXX'} Requests:data为dict,json import requests response = requests.get(url=url, params=data) Urllib2:data为string import urllib, urllib2 data = urllib.urlencode(data) full_url = url+'?'+data response = urllib2.urlopen(full_url)
|
(2)对登录情况的处理
1 2 3 4 5 6 7 8 9
| data = {'data1':'XXXXX', 'data2':'XXXXX'} Requests:data为dict,json import requests response = requests.post(url=url, data=data) Urllib2:data为string import urllib, urllib2 data = urllib.urlencode(data) req = urllib2.Request(url=url, data=data) response = urllib2.urlopen(req)
|
1 2 3
| import requests requests_session = requests.session() response = requests_session.post(url=url_login, data=data)
|
(3)反爬虫机制
限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。
1 2 3 4 5 6 7 8 9 10
| proxies = {'http':'http://XX.XX.XX.XX:XXXX'} Requests: import requests response = requests.get(url=url, proxies=proxies) Urllib2: import urllib2 proxy_support = urllib2.ProxyHandler(proxies) opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler) urllib2.install_opener(opener) response = urllib2.urlopen(url)
|
有些网站会检查你是不是真的浏览器访问,还是机器自动访问的。这种情况,加上User-Agent,表明你是浏览器访问即可。有时还会检查是否带Referer信息还会检查你的Referer是否合法,一般再加上Referer。
1 2 3 4 5 6 7 8 9
| headers = {'User-Agent':'XXXXX'} headers = {'Referer':'XXXXX'} headers = {'User-Agent':'XXXXX', 'Referer':'XXXXX'} Requests: response = requests.get(url=url, headers=headers) Urllib2: import urllib, urllib2 req = urllib2.Request(url=url, headers=headers) response = urllib2.urlopen(req)
|
3.实例分析
假设我们使用的网址是:https://movie.douban.com/top250
解释:豆瓣用户每天都在对“看过”的电影进行“很差”到“力荐”的评价,豆瓣根据每部影片看过的人数以及该影片所得的评价等综合数据,通过算法分析产生豆瓣电影 Top 250。
(1)爬取网页
爬取网页,这里的baseurl就是我们要爬虫的网页网址,调用了getData函数。
1 2
| datalist = getData(baseurl) savepath = "豆瓣电影Top250.xls"
|
接下来我们来看一下getData
函数:
1 2 3 4 5 6 7 8 9 10 11
| def getData(baseurl): datalist = []
for i in range(0, 10): """ 调用获取页面信息的函数10次 因为电影评分Top250,每个页面只显示25个,所以我们需要访问页面10次,25*10=250。 """ url = baseurl + str(i * 25) html = askURL(url)
|
这里使用了askURL
函数,我们来看看这个函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def askURL(url): head = { "User-Agent": "Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 80.0.3987.122 Safari / 537.36" }
request = urllib.request.Request(url, headers=head) html = "" try: response = urllib.request.urlopen(request) html = response.read().decode("utf-8") except urllib.error.URLError as e: if hasattr(e, "code"): print(e.code) if hasattr(e, "reason"): print(e.reason) return html
|
接下来我们继续看getData
函数剩下的内容:
(2)逐一解析数据
解析数据需要用到BeautifulSoup
这个库,下面我们就开始查找符合我们要求的数据,用BeautifulSoup
和re
库的正则表达式去匹配,匹配到符合要求的数据,然后存进datalist:
1 2 3 4 5 6 7
| findLink = re.compile(r'<a href="(.*?)">') findImgSrc = re.compile(r'<img.*src="(.*?)"', re.S) findTitle = re.compile(r'<span class="title">(.*)</span>') findRating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>') findJudge = re.compile(r'<span>(\d*)人评价</span>') findInq = re.compile(r'<span class="inq">(.*)</span>') findBd = re.compile(r'<p class="">(.*?)</p>', re.S)
|
最后我们来看最后有一步:
(3)保存数据
1 2
| saveData(datalist,savepath)
|
保存方式分类:
- xls 表, 需要(xlwt库支持)
- sqlite数据库, 需要(sqlite3库支持)