zoukankan      html  css  js  c++  java
  • scrapy相关信息

    一、scrapy基本操作

    scrapy startproject scrapy_redis_spiders  #创建项目
    cd scrapy_redis_spiders  #进入目录
    scrapy genspider chouti chouti.com   #创建爬虫项目网站
    scrapy crawl chouti --nolog   #运行爬虫,--nolog表示不打印日志

    Scrapy简介

    Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中。
    其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。

    Scrapy 使用了 Twisted异步网络库来处理网络通讯。整体架构大致如下

    Scrapy主要包括以下组件

    • 引擎(Scrapy)

       用来处理整个系统的数据流处理, 触发事务(框架核心)

    • 调度器(Scheduler)

       用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址

    • 下载器(Downloader)

         用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)

    • 爬虫(Spiders)

       爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面

    • 项目管道(Pipeline)

       负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。

    • 下载器中间件(Downloader Middlewares)

         位于Scrapy引擎和下载器之间的框架,主要是处理Scrapy引擎与下载器之间的请求及响应。

    • 爬虫中间件(Spiders Middlewares)

         介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。

    • 调度中间件(Scheduler Middlewares)

         介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应。

    Scrapy运行流程:

    1. 引擎从调度器中取出一个链接(URL)用于接下来的抓取
    2. 引擎把URL封装成一个请求(Request)传给下载器
    3. 下载器把资源下载下来,并封装成应答包(Response)
    4. 爬虫解析Response
    5. 解析出实体(Item),则交给实体管道进行进一步的处理
    6. 解析出的是链接(URL),则把URL交给调度器等待抓取

    二、Scrapy-redis基础配置

      在settings中

    
    
    ITEM_PIPELINES = {
    # 'scrapy_redis_spiders.pipelines.ScrapyRedisSpidersPipeline': 300,
    'scrapy_redis.pipelines.RedisPipeline': 300,
    'scrapy_redis_spiders.pipelines.BigfilePipeline': 400,
    }

    #
    ############ 连接redis 信息 ################# REDIS_HOST = '127.0.0.1' # 主机名 REDIS_PORT = 6379 # 端口 # REDIS_URL = 'redis://user:pass@hostname:9001' # 连接URL(优先于以上配置) REDIS_PARAMS = {} # Redis连接参数 默认:REDIS_PARAMS = {'socket_timeout': 30,'socket_connect_timeout': 30,'retry_on_timeout': True,'encoding': REDIS_ENCODING,}) # REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient' # 指定连接Redis的Python模块 默认:redis.StrictRedis REDIS_ENCODING = "utf-8" DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 有引擎来执行:自定义调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.LifoQueue' # 默认使用优先级队列(默认广度优先),其他:PriorityQueue(有序集合),FifoQueue(列表)、LifoQueue(列表) SCHEDULER_QUEUE_KEY = '%(spider)s:requests' # 调度器中请求存放在redis中的key SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat" # 对保存到redis中的数据进行序列化,默认使用pickle SCHEDULER_PERSIST = True # 是否在关闭时候保留原来的调度器和去重记录,True=保留,False=清空 SCHEDULER_FLUSH_ON_START = False # 是否在开始之前清空 调度器和去重记录,True=清空,False=不清空 # SCHEDULER_IDLE_BEFORE_CLOSE = 10 # 去调度器中获取数据时,如果为空,最多等待时间(最后没数据,未获取到)。 SCHEDULER_DUPEFILTER_KEY = '%(spider)s:dupefilter' # 去重规则,在redis中保存时对应的key chouti:dupefilter SCHEDULER_DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter' # 去重规则对应处理的类 DUPEFILTER_DEBUG = False # 深度和优先级相关 DEPTH_PRIORITY = 1 REDIS_START_URLS_BATCH_SIZE = 1 # REDIS_START_URLS_AS_SET = True # 把起始url放到redis的集合 REDIS_START_URLS_AS_SET = False # 把起始url放到redis的列表

    在spiders目录下的chouti.py中内容如下

    import scrapy
    import scrapy_redis
    from scrapy_redis.spiders import RedisSpider
    from scrapy.http import Request
    from ..items import ScrapyRedisSpidersItem
    from scrapy.selector import  HtmlXPathSelector
    
    
    from bs4 import  BeautifulSoup
    from scrapy.http.cookies import CookieJar
    import  os
    class ChoutiSpider(RedisSpider):

    name = 'chouti'
    allowed_domains = ['chouti.com']
    # start_urls = ['https://dig.chouti.com/']
    # cookies = None

    # def start_requests(self):
    # # os.environ['HTTP_PROXY'] = "192.168.10.1"
    #
    # for url in self.start_urls:
    # yield Request(url=url,callback=self.parse_index,meta={'cookiejar':True})
    # yield Request(url=url,callback=self.parse)

    def parse(self,response):
    #response.url获取url
    url = response.url

    yield Request(url=url, callback=self.parse_index, meta={'cookiejar': True}) #meta={'cookiejar': True}表示自动获取cookies

    def parse_index(self,response):
    #登录chouti
    # print(response.text)
    req = Request(
    url='https://dig.chouti.com/login',
    method='POST',
    headers={'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'},
    body='phone=86xxxxxxx&password=xxxxxx&oneMonth=1', #输入手机号跟密码
    callback=self.check_login,
    meta={'cookiejar': True}
    )
    # print(req)
    yield req

    def check_login(self,response):
    #获取主页信息
    print('check_login:',response.text)
    res = Request(
    url='https://dig.chouti.com/',
    method='GET',
    # callback=self.parse_check_login, #这个去自动点赞功能
    callback=self.parse, #这个是去下载图片功能
    meta={'cookiejar': True},
    dont_filter=True, #默认是False 默认表示去重 True表示这个url不去重
    )
    # print("res:",res)
    yield res


    def parse_check_login(self,response):
    #获取主页信息然后进行自动点赞
    # print('parse_check_login:',response.text)
    hxs = HtmlXPathSelector(response=response)
    # print(hxs)
    items = response.xpath("//div[@id='content-list']/div[@class='item']")
    # print(items)
    for item in items:
    #点赞带的share-linkid号获取所有的
    linksID = item.xpath(".//div[@class='part2']/@share-linkid").extract_first()
    # print(linksID)
    for nid in linksID:
    res = Request(
    url='https://dig.chouti.com/link/vote?linksId=%s'%nid,
    method='POST',
    callback=self.parse_show_result,
    meta={'cookiejar': True} #携带cookies
    )
    yield res

    def parse_show_result(self,response):
    print(response.text)

    def parse(self, response):
    hxs = HtmlXPathSelector(response=response)
    # 去下载的页面中:找新闻
    items = hxs.xpath("//div[@id='content-list']/div[@class='item']")
    for item in items:
    # print(item)
    href = item.xpath(".//div[@class='part1']//a[1]/@href").extract_first()
    # img = item.xpath("//div[@class='news-pic']/img/@original").extract_first()
    img = item.xpath(".//div[@class='part2']/@share-pic").extract_first()
    # print(img)
    # file_name = img.rsplit('//')[1].rsplit('?')[0]
    img_name = img.rsplit('_')[-1]
    file_path = 'images/{0}'.format(img_name)
    #使用大文件下载方式
    item = ScrapyRedisSpidersItem(url=img, type='file', file_name=file_path)
    print(img)
    yield item

    # pages = hxs.xpath("//div[@id='page-area']//a[@class='ct_pagepa']/@href").extract()
    # print(pages)
    # for page_url in pages:
    # page_url = "http://dig.chouti.com" + page_url
    # print(page_url)
    # yield Request(url=page_url, callback=self.parse)
     

    在scrapy_redis_spiders目录下载创建images目录用于存在图片

    在scrapy_redis_spiders目录下配置items.py

    # -*- coding: utf-8 -*-
    
    # Define here the models for your scraped items
    #
    # See documentation in:
    # https://doc.scrapy.org/en/latest/topics/items.html
    
    import scrapy
    
    
    class ScrapyRedisSpidersItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        url = scrapy.Field()
        img = scrapy.Field()
        type = scrapy.Field()
        file_name = scrapy.Field()

    在scrapy_redis_spiders中配置pipelines.py

    # -*- coding: utf-8 -*-
    
    # Define your item pipelines here
    #
    # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
    
    from twisted.web.client import Agent, getPage, ResponseDone, PotentialDataLoss
    
    from twisted.internet import defer, reactor, protocol
    from twisted.web._newclient import Response
    from io import BytesIO
    
    
    class ScrapyRedisSpidersPipeline(object):
        def process_item(self, item, spider):
            return item
    
    
    class _ResponseReader(protocol.Protocol):
         #与BigfilePipeline配套下载大文件
         
        def __init__(self, finished, txresponse, file_name):
            self._finished = finished
            self._txresponse = txresponse
            self._bytes_received = 0
            self.f = open(file_name, mode='wb')
    
        def dataReceived(self, bodyBytes):
            self._bytes_received += len(bodyBytes)
    
            # 一点一点的下载
            self.f.write(bodyBytes)
    
            self.f.flush()
    
        def connectionLost(self, reason):
            if self._finished.called:
                return
            if reason.check(ResponseDone):
                # 下载完成
                self._finished.callback((self._txresponse, 'success'))
            elif reason.check(PotentialDataLoss):
                # 下载部分
                self._finished.callback((self._txresponse, 'partial'))
            else:
                # 下载异常
                self._finished.errback(reason)
    
            self.f.close()
    
    
    class BigfilePipeline(object):
        """
        用于下载大文件
        """
        def process_item(self, item, spider):
            # 创建一个下载文件的任务
    
            if item['type'] == 'file':
                agent = Agent(reactor)
                d = agent.request(
                    method=b'GET',
                    uri=bytes(item['url'], encoding='ascii')
                )
                # 当文件开始下载之后,自动执行 self._cb_bodyready 方法
                d.addCallback(self._cb_bodyready, file_name=item['file_name'])
    
                return d
            else:
                return item
    
        def _cb_bodyready(self, txresponse, file_name):
            # 创建 Deferred 对象,控制直到下载完成后,再关闭链接
            d = defer.Deferred()
            d.addBoth(self.download_result)  # 下载完成/异常/错误之后执行的回调函数
            txresponse.deliverBody(_ResponseReader(d, txresponse, file_name))
            return d
    
        def download_result(self, response):
            pass

    在scrapy_redis_spiders目录下创建一个start_url.py

    #!/usr/bin/env python
    #coding=utf-8
    
    import redis
    
    conn = redis.Redis(host='127.0.0.1',port=6379)
    
    # 起始url的Key: chouti:start_urls
    conn.lpush("chouti:start_urls",'https://dig.chouti.com')
    v = conn.keys()
    # value = v.mget("chouti:start_urls")
    print(v)
  • 相关阅读:
    [非专业翻译] Mapster
    [非专业翻译] Mapster
    排序之猴子算法
    1309游客统计
    1631低洼地
    1636车牌问题
    1638图形
    这是一篇小短文
    1500【自定义函数】走楼梯
    PHP 之表单提交大数据,数据不完整
  • 原文地址:https://www.cnblogs.com/weixx1111/p/9306565.html
Copyright © 2011-2022 走看看