zoukankan      html  css  js  c++  java
  • 路飞学城-python爬虫密训-第三章

    (一)学习心得

     其实在没有正式学习python编程语言中,就知道模块是python最重要部分之一。虽然在前面HTTP协议跟IO多路复用都没有接触学的也是一知半解,scrapy模块比resquests模块功能更加强大。当然理解难度也是大了对于6月份中旬刚开始学习python基础有点难啃。11号福建福州海经历了7月史上最强一次台风,很遗憾我发现自己没有办法完成最后2次作业,突然间觉得之前自己对爬虫认知太少,计算机知识储量太少,希望在这次培训让自己进一步认识到python与爬虫,99元买了佩奇视频我也觉得很值得。希望自己下次报课是自己是做好准备了,真正跟上线上课堂。别人做到了,我却没有做到,说明我需要进步学习空间还很大。

    (二)知识点总结

    1. 高性能爬虫相关
    1)http协议本质:
    方案:
    多进程 > 多线程 > 单线程
    本质:
    sk = socket()
    # 阻塞
    sk.connect(('www.cnblogs.com',80))
    sk.sendall(b"GET /wupeiqi http1.1 ..... ")
    sk.sendall(b"POST /wupeiqi http1.1 ..... user=alex&pwd=123")
    # 阻塞
    data = sk.recv(8096)
    sk.close()
    IO多路复用:监听多个socket是否发生变化

    问题:
    - 非阻塞
    - 监听socket变化
    2)什么是异步非阻塞?
    - 非阻塞
    - 不等待(报错,捕捉异常)
    - 代码:
    sk = socket.socket()
    sk.setblocking(False)
    - 异步:
    - 回调,当达到某个指定的状态之后,自动调用特定函数。
    自定义异步非阻塞模块

    基于socket设置setblocking和IO多路复用来实现。
    爬虫发送Http请求本质创建socket对象;
    IO多路复用"循环"监听socket是否发生变化,一旦发生变化, 我们可以自定义操作(触发某个函数的执行)

    - 基于事件循环
    - 基于协程
    本质:socket+IO多路复用
    使用:
    情况一:
    import asyncio
    import requests

    @asyncio.coroutine
    def fetch_async(func, *args):
    loop = asyncio.get_event_loop()
    future = loop.run_in_executor(None, func, *args)
    response = yield from future
    print(response.url, len(response.content))

    tasks = [
    fetch_async(requests.get, 'http://www.cnblogs.com/wupeiqi/'),
    fetch_async(requests.get, 'http://dig.chouti.com/pic/show?nid=4073644713430508&lid=10273091')
    ]

    loop = asyncio.get_event_loop()
    results = loop.run_until_complete(asyncio.gather(*tasks))
    loop.close()
    情况二:
    import gevent
    from gevent import monkey
    monkey.patch_all()
    import requests

    def fetch_async(method, url, req_kwargs):
    print(method, url, req_kwargs)
    response = requests.request(method=method, url=url, **req_kwargs)
    print(response.url, len(response.content))

    # ##### 发送请求 #####
    gevent.joinall([
    gevent.spawn(fetch_async, method='get', url='https://www.cnblogs.com/', req_kwargs={}),
    gevent.spawn(fetch_async, method='get', url='https://www.baidu.com/', req_kwargs={}),
    gevent.spawn(fetch_async, method='get', url='https://www.sogo.com/', req_kwargs={}),
    ])
    # ##### 发送请求(协程池控制最大协程数量) #####
    # from gevent.pool import Pool
    # pool = Pool(None)
    # gevent.joinall([
    # pool.spawn(fetch_async, method='get', url='https://www.python.org/', req_kwargs={}),
    # pool.spawn(fetch_async, method='get', url='https://www.yahoo.com/', req_kwargs={}),
    # pool.spawn(fetch_async, method='get', url='https://www.github.com/', req_kwargs={}),
    # ])

    情况三:
    from twisted.web.client import getPage, defer
    from twisted.internet import reactor

    def all_done(arg):
    reactor.stop()

    def callback(contents):
    print(contents)

    d_list = []

    url_list = ['http://www.bing.com', 'http://www.baidu.com', ]
    for url in url_list:
    d = getPage(bytes(url, encoding='utf8'))
    d.addCallback(callback)

    d_list.append(d)

    # 用于检查是否页面已经全部下载完成,如果已下载完成那么,就停止循环。
    dlist = defer.DeferredList(d_list)
    dlist.addBoth(all_done) #

    reactor.run()

    3)什么是协程?
    协程是 “微线程” ,让一个线程 先执行某几行代码 再调到某处 执行某几行代码。

     是“微线程”,不存在;是由程序员人为创造出来并控制程序:先执行某段代码、再跳到某处执行某段代码。
    - 如果遇到非IO请求来回切换:性能更低。
    - 如果遇到IO(耗时)请求来回切换:性能高、实现并发(本质上利用IO等待的过程,再去干一些其他的事)

    如果 协程+遇到IO就切换 => 可以实现并发
    通过yield实现一个协程:
    def func1():
    print('adsfasdf')
    print('adsfasdf')
    print('adsfasdf')
    yield 1
    print('adsfasdf')
    print('adsfasdf')
    print('adsfasdf')
    yield 2
    yield 3
    yield 4
    def func2():
    print('adsfasdf')
    print('adsfasdf')
    print('adsfasdf')
    yield 11
    yield 12
    yield 19
    g1=func1()
    g2=func2()
    g1.send(None)
    g1.send(None)
    g2.send(None)
    通过greenlet模块:
    from greenlet import greenlet

    def test1():

    print 12
    gr2.switch()
    print 34
    gr2.switch()

    def test2():
    print 56
    gr1.switch()
    print 78
    gr1 = greenlet(test1)
    gr2 = greenlet(test2)
    gr1.switch()
    2.Scrapy模块

    1)安装scrapy
    scrapy是个什么鬼?
    - 帮我们提供一个可扩展功能齐全的爬虫框架。
    安装:
    Linux/mac
    - pip3 install scrapy
    Windows:
    - 安装twsited
    a. pip3 install wheel
    b. 下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
    c. 进入下载目录,执行 pip3 install Twisted-xxxxx.whl
    - 安装scrapy
    d. pip3 install scrapy -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
    - 安装pywin32
    e. pip3 install pywin32 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
    2)快速使用:
    Django:
    django-admin startproject mysite
    cd mysite
    python manage.py startapp app01
    # 写代码
    python manage.py runserver
    Scrapy:
    创建project:
    scrapy startproject xianglong
    cd xianglong
    scrapy genspider chouti chouti.com
    #写代码
    scrapy crawl chouti --nolog
    3)scrapy相关:
     spider,编写爬虫程序,去解析并处理请求。
    def parse():
    - HtmlXPathSelector
    - yield item
    - yield request
    4)item/pipelines
    配置:
    ITEM_PIPELINES = {
    'xianglong.pipelines.XianglongPipeline': 300,
    }

    使用:
    class XianglongPipeline(object):

    def process_item(self, item, spider):
    self.f.write(item['href']+' ')
    self.f.flush()

    return item

    def open_spider(self, spider):
    """
    爬虫开始执行时,调用
    :param spider:
    :return:
    """
    self.f = open('url.log','w')

    def close_spider(self, spider):
    """
    爬虫关闭时,被调用
    :param spider:
    :return:
    """
    self.f.close()

    5)去重

    配置

    DUPEFILTER_CLASS=" xianglong.dupe.MyDupe.MyDupeFilter"

    -写类

    class  MyDupeFilter(BaseDupeFilter):

    def_init_(self):

    pass

    @classmethod

    def from_settings(cls,settings):

    pass

    def request_seen(self,request):

    pass

    def open(self):#c&n return deferred

    pass

    def close(self,reason):#c&n  return  & deferred

    pass

    6)下载中间件

    配置

    DOWNLOADER_MIDDLEWARES={" xianglong.middlawaras.UserAgentDownloaderMiddlaware":543}

    class UserAgentDownloaderMiddlaware(object):

    @classmethod

    def from_crawler(cls,crawler):

    pass

    def process_request(self,request,spider):

    pass

    def process_response(self,request,response,spider):

    pass

    def process_exception(sef,request,exception,spider):

    pass

  • 相关阅读:
    浅谈线段树
    并查集最简单讲解
    mysql索引原理深度解析
    算法、数据结构可视化
    php算法题---对称的二叉树
    php算法题---连续子数组的最大和
    Jsoup一个简短的引论——采用Java抓取网页数据
    宏定义详细信息
    解决java.sql.SQLException: ORA-01789: query block has incorrect number of result columns
    BZOJ 2435 NOI2011 道路建设 BFS/DFS
  • 原文地址:https://www.cnblogs.com/christyyao/p/9285995.html
Copyright © 2011-2022 走看看