初识scrapy

2019-03-18  本文已影响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)
上一篇下一篇

猜你喜欢

热点阅读