前提
最先肯定要复习一下正则不定式,当然还可以用XPath语言去替代正则 教程
爬虫调度端:启动爬虫,停止爬虫,监视爬虫运行情况
URL管理器:对将要爬取的和已经爬取过的URL进行管理;可取出带爬取的URL,将其传送给“网页下载器”
网页下载器:将URL指定的网页下载,存储成一个字符串,在传送给“网页解析器”
网页解析器:解析网页可解析出①有价值的数据②另一方面,每个网页都包含有指向其他网页的URL,解析出来后可补充进“URL管理器”
- URL管理器的实现方式有三种,一种是python内存中,利用set()函数储存url
第二种是关联 第三种就是存放在缓存数据库中,如redis(这个不太明白 ) - 常见的网页下载器,官方的是urllib2,在py3.x后被改为urllib.request,支持登录网页的cookies处理以及代理处理),使用from urllib import
request添加模块
- 基本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# coding:utf8 #当文件中有中文时,需要声明字符集
import urllib2
import cookielib
#引用urllib2、cookielib模块
url='https://www.zhihu.com'
cj=cookielib.CookieJar()
#将查询数据赋值给变量
opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
urllib2.install_opener(opener)
#向urllib2模块添加opener
request=urllib2.Request(url)
request.add_header('user-agent','Mozilla/5.0')
response1=urllib2.urlopen(url)
print response1.getcode()
print cj
print response1.read() - 基本的urlopen()函数不支持验证、cookie或其他HTTP高级功能。要支持这些功能,必须使用build_opener()函数来创建自己的自定义Opener对象
- 网页解析器常用beatuifulsoup模块进行解析
1
2
3
4
5
6
7
8
9
10
11
12
13# coding:utf8
import urllib2
from bs4 import BeautifulSoup
url='https://www.zhihu.com'
request=urllib2.Request(url)
response1=urllib2.urlopen(url)
soup=BeautifulSoup(response1.read(),'html.parser',from_encoding="utf-8")
#第一个参数是解析出网页的代码,第二个是解析方式,第三个是用的字符集
links=soup.find_all('a')
for link in links:
print link.name,link['href'],link.get_text()
#遍历网页html代码中的a节点,并输出节点的名字、链接、对应文本
print(soup) - 通过一个简单爬虫实例来学习
控制器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#coding:utf-8
import url_manager,html_downloader,html_parser,html_outputer
class SpiderMain(object):
def __init__(self):
self.urls=url_manager.UrlManeger()
self.downloader=html_downloader.HtmlDownloader()
self.parser=html_parser.HtmlParser()
self.outputer=html_outputer.HtmlOutputer()
#初始化管理器、下载器、解析器、输出器
def craw(self,root_url):
count=1#记录爬取的次数
self.urls.add_new_url(root_url)
while self.urls.has_new_url():#如果有新的url
try:
new_url=self.urls.get_new_url() #放进一个新的url
print 'craw %d:%s'%(count,new_url)
html_cont=self.downloader.download(new_url)#下载新url对应的页面
new_urls,new_data=self.parser.parser(new_url,html_cont)#对新的url进行代码解析,又得到新的url和有效数据
self.urls.add_new_urls(new_urls)#将得到的新的url加入到url管理器进行爬取
self.outputer.collect_data(new_data)#收集有效的数据
if count==1000:#设置查找到1000个url结束爬取
break
count=count+1
except:
print 'craw failed'#标记url爬取失败
self.outputer.output_html()#输出为html形式
if __name__=="__main__":
root_url="https://baike.baidu.com/item/Python"#设置爬虫的入口url
obj_spider=SpiderMain()
obj_spider.craw(root_url)#启动爬虫管理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#coding:utf-8
class UrlManeger(object):
def __init__(self):
self.new_urls=set()#将新的url输出为一个集合并且删除重复元素
self.old_urls=set()#将新的url输出为一个集合并且删除重复元素
def add_new_url(self, url):#向管理器中添加一个新的url
if url is None: #判断url是否存在
return
if url not in self.new_urls and url not in self.old_urls: #判断url是否在待爬取或已爬取页面
self.new_urls.add(url)#将url添加到未爬取列表
def add_new_urls(self, new_urls):#向管理器中添加批量url
if new_urls is None or len(new_urls) == 0:
return
for url in new_urls:#从urls中遍历url添加到URL集合中
self.add_new_urls(url)
def has_new_url(self):#验证是否添加新的url
return len(self.new_urls) != 0
def get_new_url(self):#从管理器中拿出一个新的url进行爬取
new_url=self.new_urls.pop()#新的url集合中随机取出一个url并且从集合中删去这个url
self.old_urls.add(new_url)
return new_url解析器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26class HtmlParser(object):
def _get_new_urls(self, page_url, soup):
new_urls=set()
links=soup.find_all('a', href=re.compile(r'/item/'))#正则匹配,查询a标签中href属性
for link in links:#遍历links列表(匹配的url片段)
new_url=link['herf']#抓取herf属性值(link被储存为字典,用[]取出数据)
new_full_url=urlparse.urljoin(page_url,new_url)#将url拼接起来
new_urls.add(new_full_url)#将补全的url加入未爬取url名单
return new_urls
def _get_new_data(self, page_url, soup):
res_data={}#建立一个res_data字典
res_data['url']=page_url#加入url
title_node=soup.find('dd', class_="lemmaWgt-lemmaTitle-title").find("h1")#抓取dd标签class属性的hi属性
res_data['title']=title_node.get_text()#取得h1标签文本
sammary_node=soup.find('div', class_="lemma-summary")
res_data['sammary']=sammary_node.get_text()
return res_data#输出字典
def parser(self, new_url, html_cont):
if new_url is None or html_cont is None:#判断页面是否存在
return
soup=BeautifulSoup(html_cont, 'html_parser',from_encoding='utf-8')#以utf-8字符集解析页面html代码
new_urls=self._get_new_urls(new_url, soup)
new_data=self._get_new_data(new_url, soup)
return new_urls, new_data下载器
1
2
3
4
5
6
7
8
9
10
11
12
13#coding:utf-8
#这里只使用了最简单的方法
import urllib2#载入urllib2模块
class HtmlDownloader(object):
def download(self, url):
if url is None:#验证url是否存在
return None
response=urllib2.urlopen(url)#下载url
if response.getcode() != 200:#判断状态码
return None
res=response.read()
return res#读取网页内容输出器
这个爬取百度百科的模块是按照控制器、URL管理器、下载器、解析器、输出器分开编写的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#coding:utf-8
class HtmlOutputer(object):
def __init__(self):
self.datas=[]#设置data为一个列表
def collect_data(self,data):
if data is None:
return
self.datas.append(data)
def output_html(self):
fout=open('output.html','w')#写出一个html文件
fout.write('<html>')
fout.write('<meta charset=\'utf-8\'>')
fout.write('<body>')
fout.write('<table>')
for data in self.datas:
fout.write('<tr>')
fout.write('<td>%s</td>'%data['url'])
fout.write('<td>%s</td>'%data['title'].encode('utf-8'))
fout.write('<td>%s</td>'%data['sammary'].encode('utf-8'))
fout.write('</tr>')
fout.write('</table>')
fout.write('</body>')
fout.write('</html>')
fout.close() - 最常用的是“.text”和”.content”,前者输出unicode,后者输出二进制
- 这是PIL模块中resize函数(重新设置图片尺寸)resize((size, size), Image.ANTIALIAS)图片质量的参数
- 某些网站如知乎,存在反爬虫机制,如果要成功加载页面需要伪造头文件
- 照着网上的教程,熟悉一下itchat模块,做微信头像拼图的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68# -*- coding: utf-8 -*
import itchat
import os
from math import sqrt
from PIL import Image
itchat.auto_login()#微信登录接口
for friend in itchat.get_friends(update=True)[0:]:#获取好友列表,并保持更新
print friend['NickName'], friend['RemarkName'], friend['Sex'], friend['Province'], friend['Signature']#输出好友的基本信息
img = itchat.get_head_img(userName=friend["UserName"])#获取好友头像
path="C:\\Users\\14564\\Pictures\\pachong\\"+friend['NickName']+'('+friend['RemarkName']+').jpg'#保存获取的头像
try:
with open(path,'wb') as f:
f.write(img)
except Exception as e:
print repr(e)
def pt():
path2="C:\\Users\\14564\\Pictures\\pachong\\"
pList=[]
for item in os.listdir(path2):#遍历出单个头像
imgPath=os.path.join(path2,item)
pList.append(imgPath)#将头像图片保存到字典中
total=len(pList)#计算图片个数
line=int(sqrt(total))#计算合成图片边长
NewImage=Image.new('RGB',(128*line,128*line))#创建一个新的底片存放大小为128px的所有头像
x=0
y=0
for item in pList:
try:
Img=Image.open(item)
Img=Img.resize((128,128),Image.ANTIALIAS)#将头像图片改变大小
NewImage.paste(Img,(x*128,y*128))#不断添加头像
x+=1
except IOError:
print "第%d行,%d列文件读取失败!IOError:%s"%(y,x,item)
x-=1
if x==line:#将一行填完后移动到下一行
x=0
y+=1
if (x+line*y)==line*line:#判断
break
NewImage.save(path2+'final.jpg')#保存为final.jpg
pt()
itchat.run()
8.一个关于微信聊天机器人的程序
# -*- coding: utf-8 -*
import itchat, time, re
from itchat.content import *
import urllib2, urllib
import json
@itchat.msg_register([TEXT])#向注册方法传入msg包含text文本消息内容,这里的@是一个装饰器
def text_reply(msg):
info=msg['Text'].encode('UTF-8')#将得到的消息存放在info变量中
url='http://wwww.tuling123.com/openapi/api'#链接到图灵机器人api
data={u"key":"f0fa6a1ec8c542aeaa606a14b2ee8ecd","info":info}#post传入参数
data=urllib.urlencode(data)
url2=urllib2.Request(url,data)
response= urllib2.urlopen(url2)
apicontent=response.read()
s=json.loads(apicontent,encoding="utf-8")
print 's==',s
if s['code']==100000:
itchat.send(s['text'],msg['FromUserName'])#将从api得到的json文本发送给好友
itchat.auto_login(hotReload=True)#hotReload表示保持登录状态
itchat.run(debug=True) - 关于requests模块的一些补充
常见报错说明r.content将返回图像的二进制内容,当我们要保存到本地文件时,写入方式必须为“wb”,否则会报错1
2with open('小猪图片.jpg','wb') as f:
f.write(r.content)