python爬虫学习1

前提

  1. 最先肯定要复习一下正则不定式,当然还可以用XPath语言去替代正则 教程
    image

  2. 爬虫调度端:启动爬虫,停止爬虫,监视爬虫运行情况
    URL管理器:对将要爬取的和已经爬取过的URL进行管理;可取出带爬取的URL,将其传送给“网页下载器”
    网页下载器:将URL指定的网页下载,存储成一个字符串,在传送给“网页解析器”
    网页解析器:解析网页可解析出①有价值的数据②另一方面,每个网页都包含有指向其他网页的URL,解析出来后可补充进“URL管理器”
    image
    image

  1. URL管理器的实现方式有三种,一种是python内存中,利用set()函数储存url
    第二种是关联 第三种就是存放在缓存数据库中,如redis(这个不太明白 )
  2. 常见的网页下载器,官方的是urllib2,在py3.x后被改为urllib.request,支持登录网页的cookies处理以及代理处理),使用from urllib import

    request添加模块

  3. 基本
    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()
  4. 基本的urlopen()函数不支持验证、cookie或其他HTTP高级功能。要支持这些功能,必须使用build_opener()函数来创建自己的自定义Opener对象
  5. 网页解析器常用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)
  6. 通过一个简单爬虫实例来学习
    控制器
    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
    26
    class 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#读取网页内容
    输出器
    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()
    这个爬取百度百科的模块是按照控制器、URL管理器、下载器、解析器、输出器分开编写的
  7. 最常用的是“.text”和”.content”,前者输出unicode,后者输出二进制
  8. 这是PIL模块中resize函数(重新设置图片尺寸)resize((size, size), Image.ANTIALIAS)图片质量的参数
    image
  9. 某些网站如知乎,存在反爬虫机制,如果要成功加载页面需要伪造头文件
  10. 照着网上的教程,熟悉一下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)
  11. 关于requests模块的一些补充
    常见报错说明
    image
    1
    2
    with open('小猪图片.jpg','wb') as f:
    f.write(r.content)
    r.content将返回图像的二进制内容,当我们要保存到本地文件时,写入方式必须为“wb”,否则会报错
文章目录
  1. 1. 前提
  2. 2. request添加模块
    1. 2.0.0.1. 控制器
    2. 2.0.0.2. 管理器
    3. 2.0.0.3. 解析器
    4. 2.0.0.4. 下载器
    5. 2.0.0.5. 输出器
,