• Python Scrapy 实战


    Python Scrapy

    什么是爬虫?

    网络爬虫(英语:web crawler),也叫网络蜘蛛(spider),是一种用来自动浏览万维网的网络机器人。其目的一般为编纂网络索引。

    Python 爬虫

    在爬虫领域,Python几乎是霸主地位,将网络一切数据作为资源,通过自动化程序进行有针对性的数据采集以及处理。从事该领域应学习爬虫策略、高性能异步IO、分布式爬虫等,并针对Scrapy框架源码进行深入剖析,从而理解其原理并实现自定义爬虫框架。

    Python 爬虫爬虫框架 Scrapy

    Scrapy 是用 Python 编写实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架。Scrapy 常应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

    Python Scrapy 核心

    Scrapy Engine(引擎): 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。

    **Scheduler(调度器): **它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。

    Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理,

    Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器).

    Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。

    Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。

    Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)

    Scrapy Demo

    # 创建爬虫虚拟环境
    $ conda create --name scrapy python=3.6
    
    # 激活虚拟环境
    $ activate scrapy
    
    # 安装scrapy
    $ conda install scrapy
    
    # 使用 scrapy 提供的工具创建爬虫项目
    $ scrapy startproject myScrapy
    
    # 启动爬虫
    $ scrapy crawl scrapyName
    
    

    项目文件介绍

    • scrapy.cfg: 项目的配置文件。

    • mySpider/: 项目的Python模块,将会从这里引用代码。

    • mySpider/items.py: 项目的目标文件。

    • mySpider/pipelines.py: 项目的管道文件。

    • mySpider/settings.py: 项目的设置文件。

    • mySpider/spiders/: 存储爬虫代码目录。

    爬取豆瓣 top250

    • item.py
    import scrapy
    
    class DoubanItem(scrapy.Item):
        name = scrapy.Field()
        director = scrapy.Field()
        detail = scrapy.Field()
        star = scrapy.Field()
        synopsis = scrapy.Field()
        comment = scrapy.Field()
    
    • spiders/DoubanSpider.py
    # coding:utf-8
    
    import scrapy
    from scrapy import Request
    
    from douban.items import DoubanItem
    
    
    class DoubanSpider(scrapy.Spider):
        name = "douban"
        allowed_domains = ['douban.com']
        start_urls = ['https://movie.douban.com/top250']
    
        def parse(self, response):
            movie_list = response.xpath("//div[@class='article']/ol/li")
            if movie_list and len(movie_list) > 0:
                for movie in movie_list:
                    item = DoubanItem()
                    item['name'] = movie.xpath("./div/div[2]/div[1]/a/span[1]/text()").extract()[0]
                    item['director'] = movie.xpath("normalize-space(./div/div[2]/div[2]/p/text())").extract_first()
                    item['detail'] = movie.xpath("normalize-space(./div/div[2]/div[2]/p[1]/text())").extract()[0]
                    item['star'] = movie.xpath("./div/div[2]/div[2]/div/span[2]/text()").extract()[0]
                    item['synopsis'] = movie.xpath("normalize-space(./div/div[2]/div[2]/p[2]/span/text())").extract()[0]
                    item['comment'] = movie.xpath("./div/div[2]/div[2]/div/span[4]/text()").extract()[0]
                    yield item
    
            next_link = response.xpath("//span[@class='next']/a/@href").extract()
            if next_link:
                yield Request("https://movie.douban.com/top250" + next_link[0], callback=self.parse, dont_filter=True)
    
    
    • 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 database_handler import DatabaseHandler
    
    
    class DoubanPipeline(object):
        def __init__(self):
            self.db = DatabaseHandler(host="xxx", username="xxx", password="xxx", database="xxx")
    
        def close_spider(self, spider):
            self.db.close()
    
        # 将 Item 实例保存到文件
        def process_item(self, item, spider):
            sql = "insert into t_douban(name,director,detail,star,synopsis,comment) values('%s', '%s', '%s', '%s', '%s', '%s')" % (
                item['name'], item['director'], item['detail'], item['star'], item['synopsis'], item['comment'])
            self.db.insert(sql)
            return item
    
    
    • DatabaseHandler.py
    # coding:utf-8
    
    import pymysql
    from pymysql.err import *
    
    
    class DatabaseHandler(object):
        def __init__(self, host, username, password, database, port=3306):
            """初始化数据库连接"""
            self.host = host
            self.username = username
            self.password = password
            self.port = port
            self.database = database
            self.db = pymysql.connect(self.host, self.username, self.password, self.database, self.port, charset='utf8')
            self.cursor = None
    
        def execute(self, sql):
            """执行SQL语句"""
            try:
                self.cursor = self.db.cursor()
                self.cursor.execute(sql)
                self.db.commit()
            except (MySQLError, ProgrammingError) as e:
                print(e)
                self.db.rollback()
            else:
                print("rowCount: %s rowNumber: %s" % (self.cursor.rowcount, self.cursor.rownumber))
            finally:
                self.cursor.close()
    
        def update(self, sql):
            """ 更新操作"""
            self.execute(sql)
    
        def insert(self, sql):
            """插入数据"""
            self.execute(sql)
            return self.cursor.lastrowid
    
        def insert_bath(self, sql, rows):
            """批量插入"""
            try:
                self.cursor.executemany(sql, rows)
                self.db.commit()
            except (MySQLError, ProgrammingError) as e:
                print(e)
                self.db.rollback()
            else:
                print("rowCount: %s rowNumber: %s" % (self.cursor.rowcount, self.cursor.rownumber))
            finally:
                self.cursor.close()
    
        def delete(self, sql):
            """删除数据"""
            self.execute(sql)
    
        def select(self, sql):
            """查询数据 返回 map 类型的数据"""
            self.cursor = self.db.cursor(cursor=pymysql.cursors.DictCursor)
            result = []
            try:
                self.cursor.execute(sql)
                data = self.cursor.fetchall()
                for row in data:
                    result.append(row)
            except MySQLError as e:
                print(e)
            else:
                print(f"rowCount: {self.cursor.rowcount} rowNumber: {self.cursor.rownumber}")
                return result
            finally:
                self.cursor.close()
    
        def call_proc(self, name):
            """调用存储过程"""
            self.cursor.callproc(name)
            return self.cursor.fetchone()
    
        def close(self):
            """关闭连接"""
            self.db.close()
    
    
    if __name__ == "__main__":
        pass
    
    
    • 修改settings.py
    USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'
    
    
    ITEM_PIPELINES = {
       'mySpider.pipelines.DoubanPipeline': 300,
    }
    
    

    run

    scrapy crawl douban

  • 相关阅读:
    Android——ArrayList 、LinkList、List 区别 & 迭代器iterator的使用 & HashMap、Hashtable、LinkedHashMap、TreeMap
    Android--List与ArrayList区别(转)
    android——inflater 用法(转)
    Android——列表视图 ListView(二)SimpleAdapter
    Odoo 仓库扫码打包方案
    Odoo 仓库调拨移动过程中 单位不允许错误的分析及解决方案
    Ubuntu FTP 配置
    attrs 中的 uid
    GitLab安装手记
    [转载]How To Add Swap on Ubuntu 12.04
  • 原文地址:https://www.cnblogs.com/janlle/p/11583293.html
Copyright © 2020-2023  润新知