zoukankan      html  css  js  c++  java
  • scrapy增量爬取

    ​开始接触爬虫的时候还是初学Python的那会,用的还是request、bs4、pandas,再后面接触scrapy做个一两个爬虫,觉得还是框架好,可惜都没有记录都忘记了,现在做推荐系统需要爬取一定的文章,所以又把scrapy捡起来。趁着这次机会做一个记录。

    目录如下:

    • 环境
    • 本地窗口调试命令
    • 工程目录
    • xpath选择器
    • 一个简单的增量爬虫示例
    • 配置介绍

    环境

    ​自己的环境下安装scrapy肯定用anaconda(再次强调anaconda的优越性

    本地窗口调试与运行

    ​开发的时候可以利用scrapy自带的调试功能进行模拟请求,这样request、response都会与后面代码保持一样。

    # 测试请求某网站
    scrapy shell URL
    # 设置请求头
    scrapy shell -s USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0"  URL
    
    # 指定爬虫内容输出文件格式(json、csv等
    scrapy crawl SPIDER_NAME -o FILE_NAME.csv
    
    # 创建爬虫工程
    scrapy startproject  articles # 在当前目录创建一个scrapy工程
    

    新工程结构介绍

    # spiders文件下存放所有爬虫,item.py格式化数据输出
    # middlewares.py 设置请求细节(请求头之类的),pipelines.py为数据输出的管道,每一个封装好的item都会经过这里
    # settings.py 对工程进行全局设置(存放配置
    ├── articles
    │   ├── articles
    │   │   ├── __init__.py
    │   │   ├── items.py
    │   │   ├── middlewares.py
    │   │   ├── pipelines.py
    │   │   ├── settings.py
    │   │   └── spiders
    │   │       ├── healthy_living.py
    │   │       ├── __init__.py
    │   │       └── people_health.py
    │   └── scrapy.cfg
    ├── README.en.md
    └── README.md
    

    页面解析神器——Xpath选择器

    ​ scrapy自带xpath选择器,很方便,简单介绍一些常用的

    # 全站爬取神器--LinkExtractor,可以自动获取该标签下的所有url跟text(因为网站结构大都一个套路
    from scrapy.linkextractors import LinkExtractor
    le = LinkExtractor(restrict_xpaths="//ul[@class='nav2_UL_1 clearFix']")# 返回一个迭代器,通过循环(for i in le),可获取url(i.url)  (i.text)
    
    # 获取属性class为所有aa的div标签内容中的内容
    response.xpath("//div[@class='aa']/text()").extract()		# '//'代表获取所有,'/'代表获取第一个,类似的可以找属性为ul的其它标签
    
    # 获取内容包含“下一页”的所有a标签中包含的链接(提取下一页链接神器
    response.xpath("//a[contains(text(),'下一页')]/@href").extract()
    

    一个简单的增量爬取示例

    ​这里增量爬取的思想很简单:目标网站的数据都是按照时间排列的,所以在对某个连接进行request之前,先查询数据库中有没有这条数据,如果有,就停止爬虫,如果没有发起请求

    class HealthyLiving(scrapy.Spider):
        # 一定要一个全局唯一的爬虫名称,命令行启动的时候需要指定该名称
        name = "healthy_living"
        # 指定爬虫入口,scrapy支持多入口,所以一定是lis形式
        start_urls = ['http://www.jkb.com.cn/healthyLiving/']
    
        '''
        抓取大类标签入口
        '''
        def parse(self, response):
            le = LinkExtractor(restrict_xpaths="//ul[@class='nav2_UL_1 clearFix']")
            for link in le.extract_links(response)[1:-1]:
                tag = link.text
                # 将这一级提取到的信息,通过请求头传递给下一级(这里是为了给数据打标签
                meta = {"tag": tag}
                # 依次解析每一个链接,并传递到下一级进行继续爬取
                yield scrapy.Request(link.url, callback=self.parse_articles, meta=meta)
    
        '''
        抓取页面内的文章链接及下一页链接
        '''
        def parse_articles(self, response):
            # 接收上一级传递的信息
            meta = response.meta
            article_links = response.xpath("//div[@class='txt']/h4/a/@href").extract()
            for link in article_links:
                res = self.collection.find_one({"article_url": link}, {"article_url": 1})
                full_meta = dict(meta)
                # 将文章链接传入下一级
                full_meta.update({"article_url": link})
                if res is None:
                    yield scrapy.Request(link, callback=self.parse_article, meta=full_meta)
                else:
                    return
            next_page = response.xpath("//div[@class='page']//a[contains(text(),'»')]/@href").extract()[0]
            if next_page:
                yield scrapy.Request(next_page, callback=self.parse_articles, meta=meta)
    
    # 最后解析页面,并输出
        def parse_article(self, response):
         # 从item.py中导入数据封装格式
            article_item = ArticlesItem()
            meta = response.meta
            # 利用xpath提取页面信息并封装成item
            try:
                article_item["tag"] = ""
                #  ... 省略
            finally:
                yield article_item
    
    

    工程配置介绍

    ​设置请求头、配置数据库

    # 设置请求头,在middlewares.py中设定,在settings.py中启用
    class RandomUA(object):
        user_agents = [
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit"
                "/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36",
                "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11",
                "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit"
                "/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16"
            ]
    
        def process_request(self, request, spider):
            request.headers["User-Agent"] = random.choice(self.user_agents)
    
    
    # 设置数据入库处理,在pipeline.py进行配置,在settings.py进行启用
    class MongoPipeline(object):
        def __init__(self, mongo_uri, mongo_db):
            self.mongo_uri = mongo_uri
            self.mongo_db = mongo_db
    
        @classmethod
        def from_crawler(cls, crawler):
            return cls(
                mongo_uri=crawler.settings.get('MONGO_URI'),
                mongo_db=crawler.settings.get('MONGO_DB')
            )
    
        def open_spider(self, spider):
            print("开始爬取", datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
            self.client = pymongo.MongoClient(self.mongo_uri)
            self.db = self.client[self.mongo_db]
    
        def process_item(self, item, spider):
            data = self.db[item.collection].find_one({"title": item["title"], "date": item["date"]})
    
            if data is None:
                self.db[item.collection].insert(dict(item))
            # else:
            #     self.close_spider(self, spider)
            return item
    
        def close_spider(self, spider):
            print("爬取结束", datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
            self.client.close()
    # 在settings.py启动:请求头的修改,数据库的配置
    DOWNLOADER_MIDDLEWARES = {
       # 'articles.middlewares.ArticlesDownloaderMiddleware': 543,
       'articles.middlewares.RandomUA': 543,# 543代表优先级,数字越低优先级越高
    }
    
    ITEM_PIPELINES = {
       'articles.pipelines.MongoPipeline': 300,
    }
    
    
    # 一些其它配置
    ROBOTSTXT_OBEY = True # 是否遵守网站的robot协议
    FEED_EXPORT_ENCODING = 'utf-8' # 指定数据输出的编码格式
    ## 数据库配置
    MONGO_URI = ''
    MONGO_DB = ''
    MONGO_PORT = 27017
    MONGO_COLLECTION = ''
    
  • 相关阅读:
    netty之微信-Netty 环境配置(四)
    netty之微信-Netty 是什么?(三)
    netty之微信-IM简介(二)
    netty之微信-效果展示(一)
    为什么选择netty?
    [转]Python调用(运行)外部程序
    聚会游戏
    JavaScript点击事件-一个按钮触发另一个按钮
    文本框输入事件:onchange 、onblur 、onkeyup 、oninput
    js如何使两个input里的内容实时变化
  • 原文地址:https://www.cnblogs.com/CodeMLB/p/12088856.html
Copyright © 2011-2022 走看看