美文网首页
初识scrapy

初识scrapy

作者: 坤哥爱工作 | 来源:发表于2019-03-18 11:44 被阅读0次

    学习scrapy笔记
    链接:https://pan.baidu.com/s/1NLpLEk2cv8QbssFV-PzUTQ
    提取码:i0wv

    srapy项目搭建

    创建虚拟工作环境
    mkvirtalenv <name>
    workon <name>
    
    安装scrapy

    pip install -i https://pypi.douban.com/simple scrapy

    创建项目

    scrapy strartproject <projectname>

    创建项目模板

    scrapy genspider [options] <name> <domain>

    运行项目

    scrapy crawl <name>

    终端调试

    scrapy shell <domian>

    parcharm环境设置

    file=>settings=>Project Interpreter=>loaction选择当前项目目录=>base interpreter选择运行环境目录=>ok后会生成venv文件夹

    parcharm调试

    在项目主目录下添加main.py,debug此文件即可进入调试模式

    from scrapy.cmdline import execute
    
    import sys
    import os
    
    # 添加当前项目运行环境
    sys.path.append(os.path.dirname(os.path.abspath(__file__)))
    execute(["scrapy", "crawl", <name>])
    

    srapy选择器

    数据爬下来干嘛,当然是筛选我们想要的咯。三大法宝css选择器、xpath选择器、正则

    xpath

    语法:


    找个网页抓两个就会了,参考这篇文章
    更简便的方案:打开chorme=>F2=>右键=>copy=>copy xpath

    css

    跟前端一样,继续看他!

    scrapy Items

    爬取的主要目标就是从非结构性的数据源提取结构性数据,例如网页。 Scrapy spider可以以python的dict来返回提取的数据.虽然dict很方便,并且用起来也熟悉,但是其缺少结构性,容易打错字段的名字或者返回不一致的数据,尤其在具有多个spider的大项目中。
    Item使用简单的class定义语法以及 Field 对象来声明。例如:

    import scrapy
    
    class Product(scrapy.Item):
        name = scrapy.Field()
        price = scrapy.Field()
        stock = scrapy.Field()
        last_updated = scrapy.Field(serializer=str)
    

    参考文章

    scrapy 保存图片到本地

    1)在settings.py中打开 ITEM_PIPELINES 的注释,在 ITEM_PIPELINES 中加入

    ITEM_PIPELINES = {
       'spider_first.pipelines.SpiderFirstPipeline': 300,
       'scrapy.pipelines.images.ImagesPipeline':5,   #后面的数字代表执行优先级 ,当执行pipeine的时候会按照数字由小到大执行 
    }
    

    2)settings.py中加入

    IMAGES_URLS_FIELD ="image_url"  #image_url是在items.py中配置的网络爬取得图片地址
    #配置保存本地的地址
    project_dir=os.path.abspath(os.path.dirname(__file__))  #获取当前爬虫项目的绝对路径
    IMAGES_STORE=os.path.join(project_dir,'images')  #组装新的图片路径
     还有很多设置有特殊需要的话可以用哦 (详情可以去imagepipeine源码查看)
       IMAGES_MIN_HEIGHT=100   #设定下载图片的最小高度
       IMAGES_MIN_WIDTH=100  #设定下载图片的最小宽度
        ........
    

    3)可能报错

    ModuleNotFoundError: No module named 'PIL'
    
    安装pillow库即可
    pip install https://pypi.douban.com/simple pillow
    
    ValueError: Missing scheme in request url: h
    字段必须是list,将字段改成list即可
    

    4)获取图片保存本地的地址,则需要重写ImagesPipeline,并且在setting中调用重写的pipeline

    from scrapy.pipelines.images import ImagesPipeline
    class ArticleImagePipeline(ImagesPipeline):
        # 重载ImagePipeline中的item_completed方法,获取下载地址
    def item_completed(self, results, item, info):
    
      for ok,value in results:   #通过断点可以看到图片路径存在results内
        image_file_path=value['path'] #将路径保存在item中返回
          item['front_image_path']=image_file_path
        return item
    

    scrapy pipelines

    当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item进行处理。
    每个Item Pipeline都是实现了简单方法的Python类,比如决定此Item是丢弃而存储。以下是Item Pipeline的典型应用:

    • 验证爬取的数据(检查爬取的数据是否包含某些字段,数据清洗)
    • 查重(重复的数据丢弃)
    • 将爬取的结果保存到文件或数据库
    编写pipeline class

    在pipelines.py文件中定义一个Pipeline类,同时必须实现下面的方法:
    process_item(self,item,spider)

    Pipeline 除此之外还可以实现以下方法:
    open_spider(self, spider)
    当spider被开启是调用该方法。
    spider参数:被开启的spider对象

    close_spider(self, spider)
    当spider被关闭时,这个方法被调用
    spider参数:被关闭的spider对象

    在settings配置Item Pipeline
    ITEM_PIPELINES = {
        # 我们写好的Pipeline的路径,300表示优先级,范围(0-1000),越小级别越高
        'scrapydemo.pipelines.BaiduPipeline': 300,
    }
    

    将数据插入mysql

    安装mysqlclient
    pip install -i https://pypi.douban.com/simple mysqlclient
    同步插入

    import MySQLdb
    class MysqlPipeline(object):
        # 该方法是同步的,容易发生堵塞
        def __init__(self):
            self.conn = MySQLdb.connect(host, user, password, db, charset='utf8',
                                        use_unicode=True)
            self.cursor = self.conn.cursor()
    
        def process_item(self, item, spider):
            insert_sql = """
            insert into jobble_article(title, create_date, url, url_object_id, font_img_url, praise_nums, comment_nums, fav_nums, tags) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
            """
            self.cursor.execute(insert_sql, (item['title'], item['create_date'], item['url'], item['url_object_id'],
                                             item['font_img_url'], item['praise_nums'],
                                             item['comment_nums'], item['fav_nums'], item['tags']))
            self.conn.commit()
    

    利用twisted异步插入

    from twisted.enterprise import adbapi
    import MySQLdb.cursors
    
    class MysqlTwistedPipeline(object):
        @classmethod
        def from_settings(cls, setting):
            dbparams = dict(
                host=setting['MYSQL_HOST'],
                db=setting['MYSQL_DBNAME'],
                user=setting['MYSQL_USER'],
                password=setting['MYSQL_PASSWORD'],
                charset='utf8',
                cursorclass=MySQLdb.cursors.DictCursor,
                use_unicode=True,
            )
    
            dbpool = adbapi.ConnectionPool('MySQLdb', **dbparams)
            return cls(dbpool)
    
        def __init__(self, dbpool):
            self.dbpool = dbpool
    
        # 使用twisted将MYSQL插入变成异步执行
        def process_item(self, item, scrapy):
            query = self.dbpool.runInteraction(self.do_insert, item)
            query.addErrback(self.handle_error, item, scrapy)  # 处理异常
    
        def handle_error(self, failure, item, scrapy):
            print(failure)
    
        def do_insert(self, cursor, item):
            # 执行具体的操作
            insert_sql = """
            insert into jobble_article2(title, create_date, url, url_object_id, font_img_url, praise_nums, comment_nums, fav_nums, tags) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
            """
            cursor.execute(insert_sql, (item['title'], item['create_date'], item['url'], item['url_object_id'],
                                        item['font_img_url'], item['praise_nums'],
                                        item['comment_nums'], item['fav_nums'], item['tags']))
    

    代码优化

    scrapy提供了Itemloader,使代码看起来更加简洁和更具可配置性

    from scrapy.loader import ItemLoader
    
            item_loader = ArticleItemLoader(item=ItemLoader(), response=response)
            item_loader.add_css('title', '.entry-header h1::text')
            item_loader.add_value('url', response.url)
            item_loader.add_value('url_object_id', get_md5(response.url))
            item_loader.add_css('create_date', '.entry-meta-hide-on-mobile::text')
            item_loader.add_value('font_img_url', [font_img_url])
            item_loader.add_css('praise_nums', '.vote-post-up h10::text')
            item_loader.add_css('comment_nums', 'a[href="#article-comment"] span::text')
            item_loader.add_css('fav_nums', '.bookmark-btn::text')
            item_loader.add_css('tags', 'p.entry-meta-hide-on-mobile a::text')
            item_loader.add_css('content', '.entry')
    
            article_item = item_loader.load_item()
            yield article_item
    

    此时,将数据处理逻辑放在Item中,scrapy.Field提供两个参数input_processor, output_processor
    使用MapCompose处理输入参数

    from scrapy.loader.processors import MapCompose
    
    def date_convert(value):
        try:
            create_date = datetime.datetime.strptime(value, '%Y%m%d').date()
        except Exception as e:
            create_date = datetime.datetime.now().date()
        return create_date
    
    
    class JobboleAriticleItem(scrapy.Item):
        create_date = scrapy.Field(
            input_processor=MapCompose(date_convert),
        )
    # MapCompose会从左到右处理
    

    处理完成后参数是List,一般不是要这个的。重写ItemLoader

    from scrapy.loader import ItemLoader
    
    class ArticleItemLoader(ItemLoader):
        default_output_processor = TakeFirst()
    

    将上面实例化ItemLoader改成ArticleItemLoader

    from ArticleSpider.items import ArticleItemLoader
    
    item_loader = ArticleItemLoader(item=ItemLoader(), response=response)
    

    相关文章

      网友评论

          本文标题:初识scrapy

          本文链接:https://www.haomeiwen.com/subject/gclqmqtx.html