zoukankan      html  css  js  c++  java
  • 【Rollo的Python之路】Python Scrapy学习笔记(一)

    Scrapy:

    Scrapy使用了Twisted作为框架,Twisted有些特殊的地方是它是事件驱动的,并且比较适合异步的代码。对于会阻塞线程的操作包含访问文件、数据库或者Web、产生新的进程并需要处理新进程的输出(如运行shell命令)、执行系统层次操作的代码(如等待系统队列),Twisted提供了允许执行上面的操作但不会阻塞代码执行的方法。

    items.py 负责数据模型的建立,类似于实体类。
    middlewares.py 自己定义的中间件。
    pipelines.py 负责对spider返回数据的处理。
    settings.py 负责对整个爬虫的配置。
    spiders目录 负责存放继承自scrapy的爬虫类。
    scrapy.cfg scrapy基础配置

    今天学习了一下scrapy的抓取,做了第一个学习测试:

    Spiders

    import scrapy
    
    from quotetoturials.items import QuoteItem
    
    class QuoteSpider(scrapy.Spider):
        name = 'quote'
        allowed_domains = ['quotes.toscrape.com']
        start_urls = ["http://quotes.toscrape.com/"]
    
        def parse(self, response):
            quotes = response.css('.quote')
            for quote in quotes:
                item = QuoteItem()
                text = quote.css('.text::text').extract_first()
                author = quote.css('.author::text').extract_first()
                tags = quote.css(".tags .tag::text").extract()
                item['text'] = text
                item['author'] = author
                item['tags'] = tags
                yield item
    next
    = response.css('.pager .next a::attr(href)').extract_first() #css提取下一页 url = response.urljoin(next) #urljoin 做URL yield scrapy.Request(url=url,callback=self.parse) #callback 回调函数

    这里面有几个知识点:

      1.1 scrapy 里面的spiders 的QuoteSpider必须继承父类:scrapy.Spider。

      1.2 css 提取器规则,要学会

      1.3 xpath 方法提取也是可以的

      1.4 urljoin方法:这个方法是用来构建绝对URL的方法。

      python3对urllib和urllib2进行了重构,拆分成了urllib.request, urllib.response, urllib.parse, urllib.error等几个子模块,这样的架构从逻辑和结构上说更加合理。

    urljoin现在对应的函数是urllib.parse.urljoin

    所以引入urljoin 是:

    from urllib.parse import urljoin

      

    from urllib.parse import urljoin
    
    url1 = urljoin("http://www.baidu.com/1/aaa.html","bbbb.html")
    #直接替换url的最后一个'/'
    print(url1)
    
    url2 = urljoin("http://www.baidu.com/1/aaa.html","2/bbbb.html")
    print(url2) #直接替换url的最后一个'/'
    
    url3 = urljoin("http://www.baidu.com/1/aaa.html","/2/bbbb.html")
    print(url3) #直接替换url的最后二个'/'
    
    url4 = urljoin("http://www.baidu.com/1/aaa.html","http://www.baidu.com/3/ccc.html")
    print(url4) #第二个是完整URL就直接用第二个
    
    url5 = urljoin("http://www.baidu.com/1/aaa.html","http://www.baidu.com/ccc.html")
    print(url5) #第二个是完整URL就直接用第二个
    
    url6 = urljoin("http://www.baidu.com/1/aaa.html","javascript:void(0)")
    print(url6)  #javascript直接用
    
    执行结果:
    
    http://www.baidu.com/1/bbbb.html
    http://www.baidu.com/1/2/bbbb.html
    http://www.baidu.com/2/bbbb.html
    http://www.baidu.com/3/ccc.html
    http://www.baidu.com/ccc.html
    javascript:void(0)

      1.5 parse方法:

      parse(self,response):当请求url返回网页没有指定回调函数,默认的Request对象的回调函数,用来处理网页返回的response,和生成的Item或者Request对象,以下分析一下parse()方法的工作机制:

    1.因为使用的yield,而不是return,parse函数将会当做一个生成器使用,scrapy会注意调用parse方法中生成的结果,并且判断该结果是一个什么样的类型

    2.如果是request则会加入爬取队列中,如果是item类型则会使用pipeline处理,其他类型则会返回错误信息

    3.scrapy取到第一部分的request不会立马就去发送request,只是将这个request放到队列中,然后接着从生成器中获取

    4.取完了第一部分的request,然后再获取第二部分的item,取到item了,就会放到对应的pipeline中处理

    5.parse方法作为回调函数(callback),赋值给Request,指定parse()方法处理这些请求scrapy.Request(url,callback=self.parse)

    6.Request对象经过调度,执行生成scrapy.http.response()响应对象,并送回parse()方法,直到调度器中没有Requset(递归的思路)

    7.取尽之后,parse()工作结束,引擎再根据对列和pipeline中的内容去执行相应的操作

    8.程序在取得各个页面的items前,会先处理完之前所有的request对列的请求,然后再提取items

      1.6 callback传参:可以用lambda,可以用Request.meta传参

     

    items.py

    import scrapy
    
    class QuoteItem(scrapy.Item):
        # define the fields for your item here like:
        text = scrapy.Field()
        author = scrapy.Field()
        tags = scrapy.Field()

    这里面要了解 Field()这个对象:

    ①Field对象指明了每个字段的元数据(任何元数据),Field对象接受的值没有任何限制

    ②设置Field对象的主要目就是在一个地方定义好所有的元数据

    ③注意,声明item的Field对象,并没有被赋值成class属性。(可通过item.fields进行访问)

    ④Field类仅是内置字典类(dict)的一个别名,并没有提供额外的方法和属性。被用来基于类属性的方法来支持item生命语法。

    class dict(object):
        """
        dict() -> 创建空字典
        dict(mapping)  -> 从映射对象的键值对中初始化新字典{"key":value}
        dict(iterable) -> 从迭代器初始化字典 d[key] = value
        dict(**kwargs) -> 使用字典初始化新字典
        """
        
        # 1.清除字典内部所有内容 -> 空字典
        def clear(self):
            pass
     
        # 2.字典dict的复制
        def copy(self):
            """ dict_copy = D.copy()"""
            pass
     
        # 3.静态方法。返回一个新的字典,其中包含来自迭代器的键,以及对应的值
        @staticmethod # known case
        def fromkeys(*args, **kwargs): # real signature unknown
            pass
     
        # 4.返回指定键k的值,如果值不在字典中返回d的值
        def get(self, k, d=None): # real signature unknown; restored from __doc__
            pass
     
        # 5.以字典形式返回可遍历的(键,值)对
        def items(self): # real signature unknown; restored from __doc__
            pass
     
        # 6.以列表形式返回一个字典所有的键
        def keys(self): # real signature unknown; restored from __doc__
            pass
            
        # 7.删除字典给定键k所对应的值,返回值为被删除的值。k值必须给出。否则,返回d值。
        def pop(self, k, d=None): # real signature unknown; restored from __doc__
            pass
     
        # 8.随机返回并删除字典中的一对键和值
        def popitem(self): # real signature unknown; restored from __doc__
            pass
     
            
        # 9.和get()类似, 但如果键k不存在于字典中,将会添加键并将值设为d
        def setdefault(self, k, d=None): # real signature unknown; restored from __doc__
            pass
     
        # 10.将字典2中的键值对更新入调用字典中
        def update(self, E=None, **F): # known special case of dict.update
            """
            If E is present and has a .keys() method, then does:  for k in E: D[k] = E[k]
            If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v
            In either case, this is followed by: for k in F:  D[k] = F[k]
            """
            pass
     
        # 11.以字典的形式返回字典中所有的值
        def values(self): # real signature unknown; restored from __doc__
            """ D.values() -> an object providing a view on D's values """
            pass
     
        # 12.内置方法。判断键是否在字典中,在返回True,不在返回False
        def __contains__(self, *args, **kwargs): # real signature unknown
            pass
            
        # 13.删除字典中对应k键的值
        def __delitem__(self, *args, **kwargs): # real signature unknown
            """ Delete self[key]. """
            pass
     
        # 14.返回存在Value值得字典
        def __eq__(self, *args, **kwargs): # real signature unknown
            """ Return self==value. """
            pass
            
        def __getattribute__(self, *args, **kwargs): # real signature unknown
            """ Return getattr(self, name). """
            pass
     
        def __getitem__(self, y): # real signature unknown; restored from __doc__
            """ x.__getitem__(y) <==> x[y] """
            pass
     
        def __ge__(self, *args, **kwargs): # real signature unknown
            """ Return self>=value. """
            pass
     
        def __gt__(self, *args, **kwargs): # real signature unknown
            """ Return self>value. """
            pass
     
        def __init__(self, seq=None, **kwargs): # known special case of dict.__init__
            pass
     
        def __iter__(self, *args, **kwargs): # real signature unknown
            """ Implement iter(self). """
            pass
     
        def __len__(self, *args, **kwargs): # real signature unknown
            """ Return len(self). """
            pass
     
        def __le__(self, *args, **kwargs): # real signature unknown
            """ Return self<=value. """
            pass
     
        def __lt__(self, *args, **kwargs): # real signature unknown
            """ Return self<value. """
            pass
     
        @staticmethod # known case of __new__
        def __new__(*args, **kwargs): # real signature unknown
            """ Create and return a new object.  See help(type) for accurate signature. """
            pass
     
        def __ne__(self, *args, **kwargs): # real signature unknown
            """ Return self!=value. """
            pass
     
        def __repr__(self, *args, **kwargs): # real signature unknown
            """ Return repr(self). """
            pass
     
        def __setitem__(self, *args, **kwargs): # real signature unknown
            """ Set self[key] to value. """
            pass
     
        def __sizeof__(self): # real signature unknown; restored from __doc__
            """ D.__sizeof__() -> size of D in memory, in bytes """
            pass
     
        __hash__ = None
    

    pipelines.py

    class TextPipeline(object):
    
        def __init__(self):
            self.limit = 50
    
        def process_item(self, item, spider):
            if item['text']:
                if len(item['text']) > self.limit:
                    item['text'] = item['text'][0:self.limit].rstrip() + '...'
                return item
            else:
                return DropItem('Missing Text')
  • 相关阅读:
    【NXOpen.UF扩展】修改表达式
    NX二次开发 克隆
    C++手动加载CLR运行托管程序(CLR Hosting)
    C++/CLR 使用(VS2012,VS2013,VS2015)编写
    解决VS2015安装后stdio.h ucrtd.lib等文件无法识别问题,即include+lib环境变量配置
    NX 图标
    【错误分析】NX error status: 32
    NX CAM 读取加工参数
    CAM 模板样式表
    锁定NX原生界面 & 锁定界面更新
  • 原文地址:https://www.cnblogs.com/rollost/p/10908599.html
Copyright © 2011-2022 走看看