Scrapy爬虫框架

酥酥 发布于 2021-09-18 71 次阅读


一、新建项目

scrapy startproject 项目名

cd 到项目名

scrapy genspider 爬虫名 爬虫范围

因为scrapy很高效所以一定要有爬虫范围

二、结构概述

  1. Scheduler调度器把requests对象发送到downloader

  2. 得到response交给spiders得到requests、数据,数据部分用过spidermiddlewares(不加工)进入Item Pipeline ,requests给到scheduler

  3. Item pipeline进行数据处理

三、项目概述

1.scrapy.cfg

配置文件

两个配置项

  1. [settings]指定settings文件位置

  2. [deploy]指定url用于放到服务器上工作

2.items.py

  1. 定义要爬取的字段

3.middlewares.py

  1. 存放中间件

4.pipeline.py

如果要使用pipeline需要在settings中把pipeline相关注释给去掉,是一个字典,唯一的值是pipeline文件的位置,值是pipeline距离引擎的远近,所以一个数据可以由近及远地穿过很多pipeline。pipeline文件中的item是传入的数据集。为了让数据在pipeline中传递,一定要有return

5. settings.py

6.spider文件夹

  1. 放一些爬虫

  2. 对于某一爬虫其会有一个py文件继承自(scrapy.spider)

    1. name:爬虫名

    2. allowed_domains:允许爬取的范围

    3. start_urls:最开始爬取的url地址相应到同文件的parse

  3. parse中配合response不用etree解析直接response.xpath()就可以实现xpath解析了,然后就是配合xpath干活啦(返回Selector对象组)

  4. 值得一提的是response其实是个响应对象,调用response.text就是源码

  5. 找到后即使用了text()还是会返回一个tag佩戴着data 需要调用它的extract方法才可以,使用extract_first()或者extract[0]可以返回string但是前者找不到会返回None,后者返回空

  6. 搞定以后用yield封装数据,将会自动传到pipeline(因为用了生成器所以内存占用蛮小的)

在spider中可以返回的对象Request,BaseItem,dict,none

开始爬的命令scrapy crawl 爬虫名(小写)

 

四、Scrapy Shell

语法:scrapy shell [url]

url:可以为空、本地的一个文件(相对或绝对路径都可)、远程url地址

Scrapy Shell根据下载的页面会自动创建一些方便使用的对象,例如 Response 对象,以及 Selector 对象 (对HTML及XML内容)

  • 当shell载入后,将得到一个包含response数据的本地 response 变量,输入 response.body将输出response的包体,输出 response.headers 可以看到response的包头。
  • 输入 response.selector 时, 将获取到一个response 初始化的类 Selector 的对象,此时可以通过使用 response.selector.xpath()response.selector.css() 来对 response 进行查询。
  • Scrapy也提供了一些快捷方式, 例如 response.xpath()response.css()同样可以生效(如之前的案例)。
Selectors选择器

Scrapy Selectors 内置 XPath 和 CSS Selector 表达式机制

Selector有四个基本的方法,最常用的还是xpath:

  • xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表
  • extract(): 序列化该节点为字符串并返回list
  • css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表,语法同 BeautifulSoup4
  • re(): 根据传入的正则表达式对数据进行提取,返回字符串list列表

五、一个案例

案例说明

既然已经初步了解了scrapy的工作流程以及原理,我们来做一个入门的小案例,爬取站酷首页推荐的item信息。如下图所示,一个小方框就是一个item信息。我们要提取每一个item的六个组成部分:

  1. imgLink(封面图片链接);
  2. title(标题);
  3. types(类型);
  4. vistor(人气);
  5. comment(评论数);
  6. likes(推荐人数)

然后只是一个页面的item,我们还要通过翻页实现批量数据采集。

文件配置

目录结构

在上一篇中我们说明了新建scrapy项目(zcool)spider项目(zc),这里不再赘述,然后得到我们的目录结构如下图所示:

start.py文件

然后为了方便运行,在zcool目录下新建start文件。并进行初始化设置。

				
					from scrapy import cmdline
cmdline.execute('scrapy crawl zc'.split())
				
			
settings.py文件

在这个文件里我们需要做几样设置

避免在程序运行的时候打印log日志信息

				
					 ROBOTSTXT_OBEY = False
				
			
				
					  LOG_LEVEL = 'WARNING'
				
			
item.py文件
				
					import scrapy

class ZcoolItem(scrapy.Item):
    # define the fields for your item here like:
    imgLink = scrapy.Field() # 封面图片链接
    title = scrapy.Field() # 标题
    types = scrapy.Field() # 类型
    vistor = scrapy.Field() # 人气
    comment = scrapy.Field() # 评论数
    likes = scrapy.Field() # 推荐人数
				
			
页面数据提取
				
					def parse(self, response):
        divList = response.xpath('//div[@class="work-list-box"]/div')
        print(len(divList))
				
			
				
					def parse(self, response):
    divList = response.xpath('//div[@class="work-list-box"]/div')
    for div in divList:
        imgLink = div.xpath("./div[1]/a/img/@src").extract()[0] # 1.封面图片链接
  ...  2.title(标题);3 types(类型);4vistor(人气);5comment(评论数)  ....
        likes = div.xpath("./div[2]/p[3]/span[3]/@title").extract_first() # 6likes(推荐人数)

        item = ZcoolItem(imgLink=imgLink,title=title,types=types,vistor=vistor,comment=comment,likes=likes)

        yield item
				
			

xpath提取数据方法:

S.N.方法 & 描述
extract()返回的是符合要求的所有的数据,存在一个列表里。
extract_first()返回的hrefs 列表里的第一个数据。
get()和extract_first()方法返回的是一样的,都是列表里的第一个数据。
getall()和extract()方法一样,返回的都是符合要求的所有的数据,存在一个列表里。

注意:

get() 、getall() 方法是新的方法,extract() 、extract_first()方法是旧的方法。extract() 、extract_first()方法取不到就返回None。get() 、getall() 方法取不到就raise一个错误。

item实例创建(yield上面一行代码)

这里我们之前在目录文件配置的item文件中已经进行了设置,对于数据存储,我们在爬虫文件中开头要导入这个类:

				
					from zcool.items import ZcoolItem
				
			

为什么使用yield而不是return

不能使用return这个无容置疑,因为要翻页,使用return直接退出函数;而对于yield:在调用for的时候,函数内部不会立即执行,只是返回了一个生成器对象。在迭代的时候函数会开始执行,当在yield的时候,会返回当前值(i)。之后的这个函数会在循环中进行,直到没有下一个值。

				
					def parse(self, response):
    divList = response.xpath('//div[@class="work-list-box"]/div')
    for div in divList:
        imgLink = div.xpath("./div[1]/a/img/@src").extract()[0] # 1.封面图片链接
  ...  2.title(标题);3 types(类型);4vistor(人气);5comment(评论数)  ....
        likes = div.xpath("./div[2]/p[3]/span[3]/@title").extract_first() # 6likes(推荐人数)

        item = ZcoolItem(imgLink=imgLink,title=title,types=types,vistor=vistor,comment=comment,likes=likes)

        yield item
				
			
数据存储
				
					from itemadapter import ItemAdapter
import csv

class ZcoolPipeline:
    def __init__(self): 
        self.f = open('Zcool.csv','w',encoding='utf-8',newline='')       # line1
        self.file_name = ['imgLink', 'title','types','vistor','comment','likes']  # line2
        self.writer = csv.DictWriter(self.f, fieldnames=self.file_name)     # line3
        self.writer.writeheader()              # line4

    def process_item(self, item, spider):
        self.writer.writerow(dict(item))              # line5
        print(item)
        return item                  # line6 

    def close_spider(self,spider):
        self.f.close()