爬虫

作者: cccshuang | 来源:发表于2018-01-21 12:46 被阅读0次

    网络爬虫

    爬虫类型

    • 通用网络爬虫:如搜索引擎,面向关键字,目标是尽可能大的网络覆盖率,侧重广度
    • 聚焦网络爬虫:抓取某一特定主题相关的网络资源
    • 增量式网络爬虫:对已经爬取的网页进行增量式更新,只爬取新产生或发生变化的网页。
    • 深层网络爬虫:不能通过静态链接获取的,隐藏在搜索表单之后的,如需要登录后才可以查看到的资源。

    urllib

    from urllib import request,parse
    
    url = r'http://www.baidu.com'
    postdata = parse.urlencode([('wd','china')])  #post提交的参数
    
    #构造请求
    req = request.Request(url)
    #添加HTTP头来模拟浏览器
    req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36')
    #当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,用于页面统计和资源防盗链
    req.add_header('Referer', 'https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')
    #获得响应
    with request.urlopen(req,data=postdata.encode('utf-8')) as f:
        print(f.status)
        for k,v in f.getheaders():
            print('%s %s' %(k,v))
        print(f.read().decode('utf-8'))
    

    requests

    import requests
    
    user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36'
    headers = {'User-Agent':user_agent}
    kv = {'wd':'china'}
    r = requests.get('http://www.baidu.com/s',params=kv,headers = headers)
    print(r.status_code )
    if r.status_code ==  200:
        print(r.headers)
        print(r.headers.get('content-type'))
    else:
        r.raise_for_status()
    
    #获取cookie  
    for cookie in r.cookies.keys():
        print(cookie + ':' + r.cookies.get(cookie))
    
    print(r.url)
    print(r.content) #字节形式
    print(r.text[-100:]) #文本形式
    print(r.encoding) #根据头部信息猜测的编码方式,不一定准确
    print(r.apparent_encoding) #根据内容猜测的编码方式
    r.encoding = r.apparent_encoding
    
    import requests
    
    url = 'http://www.baidu.com'
    s = requests.Session()
    #首先访问,服务器会先分配一个cookie
    re = s.get(url,allow_redirects=True)
    
    user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36'
    headers = {'User-Agent':user_agent}
    kv = {'wd':'china'}
    #在访问就带有cookie了,不会视为非法用户
    re = s.get('http://www.baidu.com/s',params=kv,headers = headers)
    print(re.status_code )
    
    import requests
    
    url = 'http://github.com'
    proxies = {
               "http":"http://user:pass@host/",
               }
    r = requests.get(url,timeout = 2,proxies=proxies)
    print(r.history)
    
    import requests
    
    cs_url    = 'http://httpbin.org/post'
    my_data   = {
        'key1' : 'value1',
        'key2' : 'value2'
    }
    
    r = requests.post (cs_url, data = my_data)
    print(r.content)
    

    BeautifulSoup

    from _pytest.capture import unicode
    from bs4 import BeautifulSoup
    
    soup = BeautifulSoup(open('index.html'),'lxml')
    #print(soup.prettify())
    # print(soup.title)
    # print(soup.title.name)
    # soup.title.name = 'mytitle'
    # print(soup.mytitle.name)
    # print(soup.a)
    # print(soup.p.attrs)
    # print(soup.p.get('class'))
    # print('-----------------------')
    # print(soup.p.string) #NavigableString
    # unicode_str = unicode(soup.p.string)
    # print(unicode_str)
    #子节点
    # print(soup.head.contents)
    # print(soup.head.contents[0].string) #.string : 如果一个标记里面没有标记了或者只有唯一标记,则会返回最里面的内容,否则包含多个子节点,则tag无法确定,返回None
    # for child in soup.head.children:
    #     print(child)
    # for child in soup.head.descendants:
    #     print(child)
    for string in soup.strings: #.stripped_strings去掉空格和空行
        print(string)
        
    for parent in soup.a.parents:
        if parent is None:
            print('1' + parent)
        else:
            print(parent.name)
    #兄弟节点
    print(soup.p.next_sibling)
    print(soup.p.prev_sibling)
    for sibling in soup.a.next_siblings:
        print(repr(sibling))
    #前后节点
    for ele in soup.a.next_elements:
        print(ele)
    
    from _pytest.capture import unicode
    from bs4 import BeautifulSoup
    import re
    from pip._vendor.distlib._backport.tarfile import TUREAD
    
    soup = BeautifulSoup(open('index.html'),'lxml')
    
    print(soup.findAll('b')) #寻找所有的<b>标记
    print(soup.findAll(re.compile('^b'))) #寻找所有以b开头的标记
    print(soup.findAll(['a','b'])) #找到所有的a标记和b标记
    print(soup.findAll(True)) #找到所有tag
     
    def hasClass_Id(tag):
        return tag.has_attr('class') and tag.has_attr('id')
    print(soup.findAll(hasClass_Id)) #定义过滤器,找到包含class和id属性的元素
      
    #-------------------------------
    print(soup.findAll(id='link1'))
    print(soup.findAll(href=re.compile("163"))) #查找href属性含有“163”的tag
    print(soup.findAll('a',class_='py1')) #用class过滤
     
    data_soup = BeautifulSoup('<div data-foo="value">foo!</div>','lxml')
    print(data_soup.find_all(attrs={"data-foo":"value"}) )#定义字典参数来搜索包含特殊属性的tag
    print(soup.find_all('a',text=re.compile('^A'))) #text参数用来搜索字符串
    print(soup.find_all('title',recursive=False)) #只搜索tag的直接子节点
    

    xpath,css选择器

    from _pytest.capture import unicode
    from bs4 import BeautifulSoup
    import re
    from pip._vendor.distlib._backport.tarfile import TUREAD
    
    soup = BeautifulSoup(open('index.html'),'lxml')
    #css选择器
    print(soup.select("title")) #直接插找title标记
    
    print(soup.select("html head title")) #逐层查找title
    
    print(soup.select("head > title")) #查找head下的title
    print(soup.select("p > # link1")) #查找p下id为link1的标记
    
    print(soup.select(".course")) #根据css类名查找
    print(soup.select("# link1")) #根据tag的id找
    print(soup.select('a[href]')) #根据是否存在某个属性来查找
    
    import json
    
    from bs4 import BeautifulSoup
    import requests
    
    
    url = 'http://seputu.com/'
    user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36'
    headers = {'User-Agent':user_agent}
    r = requests.get(url,headers=headers)
    r.encoding = r.apparent_encoding
    # print(r.text)
    soup = BeautifulSoup(r.text,'html.parser',from_encoding='utf-8')
    content = []
    for mulu in soup.findAll(class_='mulu'):
        h2 = mulu.find('h2')
        if h2 != None:
            h2_title = h2.string
            list = []
            for a in mulu.find(class_='box').find_all('a'):
                href = a.get('href')
                box_title = a.get('title')
                list.append({'href':href,'box_title':box_title})
            content.append({'title':h2_title,'content':list})
    with open('qiye.json','w') as fp:
        json.dump(content,fp=fp,indent=4)
    
    import csv
    import json
    import re
    
    from bs4 import BeautifulSoup
    import requests
    
    
    url = 'http://seputu.com/'
    user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36'
    headers = {'User-Agent':user_agent}
    r = requests.get(url,headers=headers)
    r.encoding = r.apparent_encoding
    # print(r.text)
    soup = BeautifulSoup(r.text,'html.parser',from_encoding='utf-8')
    
    pattern = re.compile(r'\s*\[(.*)\]\s+(.*)')
    rows = []
    for mulu in soup.findAll(class_='mulu'):
        h2 = mulu.find('h2')
        if h2 != None:
            h2_title = h2.string
     
            for a in mulu.find(class_='box').find_all('a'):
                href = a.get('href')
                box_title = a.get('title')           
                match = pattern.search(str(box_title))
                if match != None:
                    date = match.group(1)
                    real_title = match.group(2)
                    content = (h2_title,real_title,href,date)
                    print(content)
                    rows.append(content)
    result_header = ['title','real_title','href','date']
    with open('qiye.csv','w') as f:
        f_csv = csv.writer(f,)
        f_csv.writerow(result_header)
        f_csv.writerows(rows)
    

    爬取图片等多媒体文件 urllib.request.urlretrieve

    
    import csv
    import json
    import re
    import urllib
    
    from bs4 import BeautifulSoup
    import requests
    
    def schedue(a,b,c):  
        '''''回调函数 
        @a:已经下载的数据块 
        @b:数据块的大小 
        @c:远程文件的大小 
        '''  
        per=100.0*a*b/c  
        if per>100:  
            per=100  
        print('%.2f%%' % per)
    
    url = 'http://www.ivsky.com/bizhi/fengjing/'
    user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36'
    headers = {'User-Agent':user_agent}
    r = requests.get(url,headers=headers)
    r.encoding = r.apparent_encoding
    # print(r.text)
    soup = BeautifulSoup(r.text,'html.parser',from_encoding='utf-8')
    
    
    for tupian in soup.findAll(class_='left'):
        for img in tupian.findAll('img'):
            urllib.request.urlretrieve(img.get('src'),img.get('alt')+'.jpg',schedue)
    

    基础爬虫框架

    五大模块:

    • 爬虫调度器
    • URL管理器:链接去重:1)内存去重,如set; 2)关系数据库去重; 3)缓存数据库去重,大部分成熟爬虫采用。
    • HTML下载器、
    • HTML解析器、
    • 数据存储器

    动态网站抓取

    动态网站数据是局部更新。
    两种做法:

    • 直接从JavaScript采集加载的数据
    • 直接采集浏览器中加载好的数据

    网页登录POST分析

    利用Chrome浏览器F12控制台Network,Serarch进行分析。
    如登陆,如果用户名和密码都是用的明文传输,在手动登陆的时候有个小技巧,那就是故意把密码填错,这样可以很容易看到用户名和密码正确的提交路径和提交方式。注意要在打开目标网站登陆界面之前就要打开抓包工具,因为一般加密登陆用户名和密码的js代码在用户登陆之前就被请求了。如果在手动登陆的过程再打开,那么可能就找不到它的JS加密文件了。这种情况一般用于加密提交用户名和密码的时候。

    POST中的参数只有三种情况:

    1. 在源代码页面中的
    2. 是通过服务器返回的
    3. 通过运行js生成的 。
      这部分还没能够完全掌握,仍需要好好练习。
      参考:
      微博模拟登录
      百度云盘模拟登录

    验证码问题

    1. IP代理
      使用开源项目IPProxyPool代理池
    import requests
    import json
    r = requests.get('http://127.0.0.1:8000/?types=0&count=5&country=国内')
    ip_ports = json.loads(r.text)
    print(ip_ports)
    ip = ip_ports[0][0]
    port = ip_ports[0][1]
    proxies={
        'http':'http://%s:%s'%(ip,port),
        'https':'http://%s:%s'%(ip,port)
    }
    r = requests.get('http://ip.chinaz.com/',proxies=proxies)
    r.encoding='utf-8'
    print(r.text)
    
    1. Cookie登录
      将cookie信息保存到本地,可以保存一段时间,下次登录直接使用cookie。
    2. 传统验证码识别
      使用图像识别。
    3. 人工打码
      打码兔,QQ超人打码等平台,自动识别+人工识别的组合方式。
    4. 滑动验证打码
      使用selenium:
    • 在浏览器上模拟鼠标拖动
    • 计算图片中缺口偏移
    • 模拟人类拖动鼠标的轨迹
      还可以采取多账号登录后,保存cookie信息,组建cookie池。
      一般爬取难度 :www > m > wap

    终端协议分析

    当网页抓取困难时,可以考虑PC端或者APP端。
    PC端可以使用HTTPAnalyzer分析获取数据api;
    app可以在模拟器上使用,然后使用Wireshark抓包分析。

    Scrapy

    各大组件和功能:

    • Scrapy引擎(Engine):控制数据流在系统的所有组件中流动,并在相应动作发生时触发事件。
    • 调度器(Scheduler):从引擎接收request并让它们入队,一般以后引擎请求request时提供给引擎。
    • 下载器(Downloader)
    • Spider :用户编写用于分析Response并提取item或额外跟进的url的类。相当于Html解析器
    • Item Pipeline:负责处理Spider提取出的item,如清理验证及持久化(如存储在数据库中)。相当于数据存储器。
    • 下载器中间件(Downloader middlewares):引擎与下载器之间的特定钩子,处理下载器传递给引擎的response。
    • Spider中间件(Spider middlewares):引擎与Spider之间的特定钩子,处理Spider的输入(response)和输出(Itme及requests)。

    windows下安装

    需要

    • pywin32
    • pyOpenSSL:下载完成后运行python setup.py install
    • lxml:pip install lxml' 最后安装Scrapy:pip install Scrapywindows上安装Scrapy确实比较坑,Scrapy依赖Twisted,尤其是在安装Twisted中会出现问题。 在我安装的过程中,直接使用pip install Scrapy` 进行安装时,直接pip install需要在本地进行编译,我电脑上studio 2015各种报错,比如
    error: command 'cl.exe' failed: No such file or directory
    

    在网上搜了好多,最终在知乎找到了一种“曲线救国”的解决办法,如下:

    Python Extension Packages for Windows
    去上面地址下载你对应版本cp35的whl,注意,虽然你系统是64位,但要看清你python版本是32还是64位的,再下载对应的win32或者amd64文件
    安装wheel
    pip install wheel
    进入.whl所在的文件夹,执行命令即可完成安装
    pip install 带后缀的完整文件名

    然后再使用pip install Scrapy 去安装就ok啦。

    相关文章

      网友评论

        本文标题:爬虫

        本文链接:https://www.haomeiwen.com/subject/nqbfaxtx.html