杂乱无章的scrapy细碎知识

 

1.

    def parse(self, response):

        #获取响应头
        print(response.headers)
        #获取状态码
        print(response.status)
        #获取响应的二进制数据
        print(response.body)
        #获取响应的字符串数据
        print(response.text)

2. Scrapy优势:用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容及图片。非常方便,另外它使用了Twisted这个异步网络框架来处理网络通讯,不用我们自己实现异步框架,除此之外,它还包含了各种中间件接口,可以灵活的实现各种需求。

3. 图片下载setting配置 :

#当项目需要启动pipeline的时候,不管是自定义的pipeline或者是scrapy自带的pipeline都需要在ITEM_PIPELINES里面进行配置
ITEM_PIPELINES = {
   # 'ImageSpider.pipelines.ImagespiderPipeline': 150,
   #  'ImageSpider.pipelines.FilespiderPipeline':200,
    #数字表示是通过pipeline管道的优先级,数字越小,优先级越高
    'scrapy.pipelines.images.ImagesPipeline': 1
}
#IMAGES_STORE是在设置图片的存储路径,也可以设置为绝对路径
IMAGES_STORE="imgs"
#IMAGES_URLS_FIELD是在配置爬虫根据item对象中的哪一个字段进行url的请求,对图片进行下载
IMAGES_URLS_FIELD='src'
#图像管道避免下载最近已经下载的图片置IMAGES_EXPIRES可以调整失效期限,可以用天数来指定:
IMAGES_EXPIRES=7
#图片管道可以自动创建下载图片的缩略图。
IMAGES_THUMBS={
    'small':(30,30),
    'big':(100,100)
}
# # 如果只想要宽度大于250的图片,只需IMAGES_MIN_HEIGHT 和 IMAGES_MIN_WIDTH 设置中指定最小允许的尺寸。
IMAGES_MIN_HEIGHT = 0
IMAGES_MIN_WIDTH = 250
# # 生成后的目录结构如下
- imgs
  -full    #原图
  -thumbs   #设定好大小的略缩图

4. items.py中的设置

import scrapy

class NovelspiderItem(scrapy.Item):
    #NovelspiderItem这个item类继续成scrapy.Item这个类,NovelspiderItem这个类的主要作用就声明一个字典类型的对象,可以实现类似于字典对象的存储和读取。
    #novel_name,novel_info,novel_type,novel_author这些相当于是字典对象中的键。
    novel_name=scrapy.Field()
    novel_info=scrapy.Field()
    novel_type=scrapy.Field()
    novel_author=scrapy.Field()

5. 通过命令储存item字段

#scrapy自带的命令可以将yield item返回的item对象生成Json文件保存到本地进行存储。保存的时候,网页解析的数据是Unicode编码,需要转出成utf-8编码之后再进行存储
#命令:scrapy crawl novel -o 文件名.json -s FEED_EXPORT_ENCODING=utf-8
#命令:scrapy crawl novel -o novel1.csv scrapy自带的存储为csv文件的api
#命令:scrapy crawl novel -o novel.xml scrapy自带的存储为xml文件的api
#命令:scrapy crawl novel -o novel.jsonlines 将存储的json文件中的每一个item都输出一行

#使用scrapy自带的scrapy crawl novel -o novel.csv 将数据存为csv文件时,发现文件有空行的解决方法:
#找到scrapy/exporters.py文件,找到CsvItemExporter类,在io.TextIOWrapper函数的参数里增加参数 newline=''

6. pipelines.py自定义

  1.   文件下载
    1.   通过访问url直接获得下载文件时(比如小说网站的下载按钮,或者图片),可以使用scrapy内置的pipelines; 这时,不用再pipelines.py中写逻辑,只需要在settings.py中配置就好
    2. ITEM_PIPELINES = {
         # 'QiShuSpider.pipelines.QishuspiderPipeline': 300,
          #scrapy自带的图片下载pipeline
          'scrapy.pipelines.images.ImagesPipeline': 1,
          # scrapy自带的文件下载pipeline
          'scrapy.pipelines.files.FilesPipeline': 2
      }
      #设置图片的存储位置
      IMAGES_STORE='imgs'
      IMAGES_URLS_FIELD='novel_img_url'
      
      #设置文件的存储位置
      FILES_STORE='files'
      FILES_URLS_FIELD='novel_download_url'
      #目录结构如3
  2.   自定义图片下载, 需要重写ImagesPipeline中的方法
    1.   这个类继承了ImagesPipeline, 重写了其中的两个方法
    2.   在get_media_requests方法中设定请求图片的url(替代了在settings.py中的IMAGES_URLS_FIELD='itemurl字段'这一步)
    3.   在file_path方法中设置图片下载的 路径 以及 名称
    4.   重写ImagesPipeline的类:
      import scrapy
      from scrapy.pipelines.images import ImagesPipeline
      
      #
      # class ZhanzhangsucaispiderPipeline(object):
      #     def process_item(self, item, spider):
      #         return item
      #自定义图片存储pipeline,是基于Scrapy自带的ImagesPipeline实现的,只需要在ImagesPipeline的基础上,重写图片的保存路径和图片的名称相对应的方法。
      class CustomImagePipeline(ImagesPipeline):
          #重写Scrapy自带的ImagesPipeline中get_media_requests这个方法的主要目的是,是为了通过Request对象给file_path传递一个item,这个item里面包含着图片分类的名称和图片的url地址
          def get_media_requests(self, item, info):
              for image_url in item['download_url']:
                  yield scrapy.Request(image_url,meta={"item":item})
      
          #Scrapy自带的ImagesPipeline中实现图片存储路径和图片名称的关键方法就是file_path,这也就代表着想要自定义图片存储路径和图片名称,就可以考虑重写ImagesPipeline中的file_path这个方法,就可以达到想要的结果。
      
          def file_path(self, request, response=None, info=None):
              #file_path这个函数的参数request接收到的就是传过来的Request对象,只需要通过request调用meta属性即可拿到Request对象传递过来的item对象,再通过解析item对象,即可获取相对应的图标分类名称和每张图标图片对应的地址。再通过图标分类名称和图标图片的地址创建文件存储路径即可。
              '''
              用于自定义图片的存储文件夹和图片的名称
              :return: 路径
              '''
              item=request.meta["item"]
              #从item对象当中取出图片的url,取出每个小分类的名称
              title=item["title"]
              image_name=item["download_url"][0].split("/")[-1]
              path="%s/%s"%(title,image_name)
              return path
  3.   自定义pipeline用各种方式(数据库,json,csv等)存储item
    1.   重点有三个方法,一个__init__方法,一个有装饰器的方法
    2.   三个方法分别是open_spider, process_item, close_spider ,其中open_spider方法在爬虫开始时启动,close_spider结束时启动,前者可以写开启某个数据库,csv等文件,后者则关闭相关数据库,csv等文件.  process_item是重写pipeline必须实现的一个方法,里面实现了对item的处理方式,但是返回值仍然是item,只是对item做了处理,使爬虫在传递item的时候同时使用我们设定的方法存储数据.
    3. __init__方法中初始化类变量,from_crawler方法主要功能是从settings.py中读取相关配置
    4. import json
      import codecs
      import csv
      
      #自定义的每一个itempipeline必须是一个独立的Python类,也就是继承于object
      class NovelspiderPipeline(object):
          def __init__(self):
              #初始化函数只执行一次
              self.f=codecs.open(filename="novel.json",mode="w",encoding="utf-8")
              self.f.write("[")
              print("初始化函数执行了")
      
          def open_spider(self,spider):
              #open_spider只执行一次
              # self.f = codecs.open(filename="novel.json", mode="w", encoding="utf-8")
              #当爬虫开启的时候,这个函数会被调用
              print("%s-爬虫启动了"%spider.name)
      
      
          def process_item(self, item, spider):
              '''
              process_item这个方法是必须要实现的,也就是说想要自定义一个itempipeline,这个方法是必须要使用的。而且从spider中yield过来的item都必须要经过process_item这个函数来处理,每传递过来一个item这个函数就会被执行一次。
              :param item: 每一个从spider中yield过来的item。
              :param spider: 当前的爬虫(指代的是哪一个爬虫)
              :return: 当process_item每处理完一个item,最后都要将这个item返回出去,因为后续可能还有其他的函数需要处理这个item。
              '''
              print("process_item执行了")
              #由于item并不真正的字典,它是一个NovelSpiderItem类型的数据,所有需要进行转换
              item_dict=dict(item)
              #因为json.dumps在序列化的时候回对中文默认使用ascii编码,想要真正输出中文需要设置ensure_ascii=False
              json_str=json.dumps(item_dict,ensure_ascii=False)
              self.f.write(json_str+",")
              return item
      
          def close_spider(self,spider):
              #close_spider只执行一次
              self.f.seek(self.f.tell()-1)
              self.f.write("]")
              self.f.close()
              #当爬虫结束时,该函数会被调用
              print("%s-爬虫关闭了"%spider.name)
      
          # @classmethod
          # def from_crawler(cls,crawler):
          #     #主要功能是从settings文件中读取相关配置的。
          #     pass
      
      class NovelSpiderCSVPipeline(object):
          def open_spider(self,spider):
              self.f=open("novel.csv","w",encoding="utf-8",newline="")
              self.writer=csv.DictWriter(self.f,fieldnames=["novel_name","novel_info","novel_type","novel_author"])
              self.writer.writeheader()
      
          def process_item(self,item,spider):
              item_dict=dict(item)
              self.writer.writerow(item_dict)
              return item
      
          def close_spider(self,spider):
              self.f.close()

7. pipelines存储在mysql中

from jobspider.items import *
import pymysql

class JobspiderPipeline(object):
    def __init__(self):
        # 1. 建立数据库的连接
        self.connect = pymysql.connect(
            host='localhost',
            port=3306,
            user='',
            passwd='',
            db='',
            charset='utf8'
        )
        # 2. 创建一个游标cursor, 是用来操作表。
        self.cursor = self.connect.cursor()

    def process_item(self, item, spider):
        if isinstance(item, ZhiHuItem):
            pass
        elif isinstance(item, JobspiderItem):
            # 3. 将Item数据放入数据库,默认是同步写入。
            # INSERT INTO job(zwmc); DELETE DATABASE job; VALUES ('123') SQL注入
            insert_sql = "INSERT INTO job(zwmc, zwxz, zpyq, gwyq) VALUES ('%s', '%s', '%s', '%s')" % (item['zwmc'], item['zwxz'], item['zpyq'], item['gwyq'])
            self.cursor.execute(insert_sql)

            # 4. 提交操作
            self.connect.commit()

    def close_spider(self, spider):
        self.cursor.close()
        self.connect.close()

8. re_first

        # re_first(): 直接将css返回列表中的第一个元素的数字提取出来
        total_page_num = int(response.css('.td::text').re_first('共(\d+)页'))

9.

 

posted @ 2018-12-19 17:40  陈桑啊丶  阅读(353)  评论(0编辑  收藏  举报