猫哥教你写爬虫 047--scrapy框架

栏目: 编程工具 · 发布时间: 6年前

以前我们写爬虫,要导入和操作不同的模块,比如requests模块、gevent库、pymysql模块等。而在Scrapy里,你不需要这么做,因为很多爬虫需要涉及的功能,比如麻烦的异步,在Scrapy框架都自动实现了

我们之前编写爬虫的方式,相当于在一个个地在拼零件,拼成一辆能跑的车。而Scrapy框架则是已经造好的、现成的车,我们只要踩下它的油门,它就能跑起来。这样便节省了我们开发项目的时间

猫哥教你写爬虫 047--scrapy框架

Scrapy的结构

猫哥教你写爬虫 047--scrapy框架

Scheduler (调度器)部门主要负责处理引擎发送过来的requests对象(即网页请求的相关信息集合,包括params,data,cookies,request headers…等),会把请求的url以有序的方式排列成队,并等待引擎来提取(功能上类似于gevent库的queue模块)。

Downloader (下载器)部门则是负责处理引擎发送过来的requests,进行网页爬取,并将返回的response(爬取到的内容)交给引擎。它对应的是爬虫流程【获取数据】这一步。

Spiders (爬虫)部门是公司的核心业务部门,主要任务是创建requests对象和接受引擎发送过来的response(Downloader部门爬取到的内容),从中解析并提取出有用的数据。它对应的是爬虫流程【解析数据】和【提取数据】这两步。

Item Pipeline (数据管道)部门则是公司的数据部门,只负责存储和处理Spiders部门提取到的有用数据。这个对应的是爬虫流程【存储数据】这一步。

Downloader Middlewares (下载中间件)的工作相当于下载器部门的秘书,比如会提前对引擎大boss发送的诸多requests做出处理。

Spider Middlewares (爬虫中间件)的工作则相当于爬虫部门的秘书,比如会提前接收并处理引擎大boss发送来的response,过滤掉一些重复无用的东西。

猫哥教你写爬虫 047--scrapy框架

scrapy 工作原理

在Scrapy爬虫公司里,每个部门都各司其职,形成了很高效的运行流程

猫哥教你写爬虫 047--scrapy框架

Scrapy中的程序全部都是异步模式,所有的请求或返回的响应都由引擎自动分配去处理

Scrapy的用法(豆瓣读书top250)

猫哥教你写爬虫 047--scrapy框架

book.douban.com/top250

分析分页...

猫哥教你写爬虫 047--scrapy框架

分析元素...

我们只要取出 <tr class="item"> 元素下 <a> 元素的 title 属性的值、 <p class="pl"> 元素、 <span class="rating_nums"> 元素,就能得到书名、出版信息和评分的数据。

猫哥教你写爬虫 047--scrapy框架

代码实现——创建项目

安装scrapy, pip install scrapy

猫哥教你写爬虫 047--scrapy框架

解决方案1: 安装vc++运行库集合

pan.baidu.com/s/16jVqbrHA… u2v6

猫哥教你写爬虫 047--scrapy框架

方案2: 直接下载whl库进行安装, 简单 , 最近需要翻墙, 不知道以后怎样...

猫哥教你写爬虫 047--scrapy框架
猫哥教你写爬虫 047--scrapy框架

方案3: 安装vc++2015, 对应14版本, 试了,不管用, 你就别试了...

猫哥教你写爬虫 047--scrapy框架
猫哥教你写爬虫 047--scrapy框架

创建爬虫项目

跳转到你想创建爬虫项目的路径

猫哥教你写爬虫 047--scrapy框架

创建爬虫项目

猫哥教你写爬虫 047--scrapy框架

项目结构

猫哥教你写爬虫 047--scrapy框架

Scrapy项目里每个文件都有特定的功能,settings.py 是scrapy里的各种设置。items.py是用来定义数据的,pipelines.py是用来处理数据的,它们对应的就是Scrapy的结构中的Item Pipeline(数据管道)middlewares.py是中间件

代码实现——编辑爬虫

如前所述,spiders是放置爬虫的目录。我们可以在spiders这个文件夹里创建爬虫文件。我们来把这个文件,命名为top250。后面的大部分代码都需要在这个top250.py文件里编写。

猫哥教你写爬虫 047--scrapy框架

E:\helloSpider\douban\douban\spiders\top250.py

import scrapy
import bs4
# 定义一个爬虫类DoubanSpider。就像我刚刚讲过的那样,DoubanSpider类继承自scrapy.Spider类。
class DoubanSpider(scrapy.Spider):
    # name是定义爬虫的名字,这个名字是爬虫的唯一标识。name = 'douban'意思是定义爬虫的名字为douban。等会我们启动爬虫的时候,要用到这个名字。
    name = 'douban'
    # allowed_domains是定义允许爬虫爬取的网址域名(不需要加https://)。如果网址的域名不在这个列表里,就会被过滤掉。
    allowed_domains = ['book.douban.com']
    # start_urls是定义起始网址,就是爬虫从哪个网址开始抓取。在此,allowed_domains的设定对start_urls里的网址不会有影响。
    start_urls = ['https://book.douban.com/top250?start=0']
    # parse是Scrapy里默认处理response的一个方法
    def parse(self,response):
        print(response.text)
复制代码

之前分析过页面规律

猫哥教你写爬虫 047--scrapy框架

十页变一页...

猫哥教你写爬虫 047--scrapy框架

修改代码...

import scrapy
import bs4
# 定义一个爬虫类DoubanSpider。就像我刚刚讲过的那样,DoubanSpider类继承自scrapy.Spider类。
class DoubanSpider(scrapy.Spider):
    # name是定义爬虫的名字,这个名字是爬虫的唯一标识。name = 'douban'意思是定义爬虫的名字为douban。等会我们启动爬虫的时候,要用到这个名字。
    name = 'douban'
    # allowed_domains是定义允许爬虫爬取的网址域名(不需要加https://)。如果网址的域名不在这个列表里,就会被过滤掉。
    allowed_domains = ['book.douban.com']
    # start_urls是定义起始网址,就是爬虫从哪个网址开始抓取。在此,allowed_domains的设定对start_urls里的网址不会有影响。
    start_urls = []
    for x in range(3):
        url = 'https://book.douban.com/top250?start='+str(x*25)
        start_urls.append(url)
    # parse是Scrapy里默认处理response的一个方法
    def parse(self,response):
        print(response.text)
复制代码
猫哥教你写爬虫 047--scrapy框架

提取元素....

书名是 <tr class="item"> 元素下 <a> 元素的 title 属性的值;出版信息在 <p class="pl"> 元素里;评分在 <span class="rating_nums"> 元素里。

import scrapy
import bs4
from ..items import DoubanItem
# 定义一个爬虫类DoubanSpider。就像我刚刚讲过的那样,DoubanSpider类继承自scrapy.Spider类。
class DoubanSpider(scrapy.Spider):
    # name是定义爬虫的名字,这个名字是爬虫的唯一标识。name = 'douban'意思是定义爬虫的名字为douban。等会我们启动爬虫的时候,要用到这个名字。
    name = 'douban'
    # allowed_domains是定义允许爬虫爬取的网址域名(不需要加https://)。如果网址的域名不在这个列表里,就会被过滤掉。
    allowed_domains = ['book.douban.com']
    # start_urls是定义起始网址,就是爬虫从哪个网址开始抓取。在此,allowed_domains的设定对start_urls里的网址不会有影响。
    start_urls = []
    for x in range(3):
        url = 'https://book.douban.com/top250?start='+str(x*25)
        start_urls.append(url)
    # parse是Scrapy里默认处理response的一个方法
    def parse(self, response):
        bs = bs4.BeautifulSoup(response.text, 'html.parser')
        datas = bs.find_all('tr', class_='item')
        for data in datas:
            title = data.find_all('a')[1]['title']
            publish = data.find('p', class_="pl").text
            score = data.find('span', class_="rating_nums").text
            print([title, publish, score])
复制代码

代码实现——定义数据

在scrapy中,我们会专门定义一个用于记录数据的类。

我们会实例化一个对象,利用这个对象来记录数据。

每一次,当数据完成记录,它会离开 spiders ,来到Scrapy Engine(引擎),引擎将它送入Item Pipeline(数据管道)处理。

定义这个类的py文件,正是 items.py

如何在items.py里定义这些数据。代码如下:

import scrapy
class DoubanItem(scrapy.Item):
    # 让数据能以类似字典的形式记录
    title = scrapy.Field()
    publish = scrapy.Field()
    score = scrapy.Field()
复制代码

修改douban250.py

import scrapy
import bs4
from ..items import DoubanItem
# 定义一个爬虫类DoubanSpider。就像我刚刚讲过的那样,DoubanSpider类继承自scrapy.Spider类。
class DoubanSpider(scrapy.Spider):
    # name是定义爬虫的名字,这个名字是爬虫的唯一标识。name = 'douban'意思是定义爬虫的名字为douban。等会我们启动爬虫的时候,要用到这个名字。
    name = 'douban'
    # allowed_domains是定义允许爬虫爬取的网址域名(不需要加https://)。如果网址的域名不在这个列表里,就会被过滤掉。
    allowed_domains = ['book.douban.com']
    # start_urls是定义起始网址,就是爬虫从哪个网址开始抓取。在此,allowed_domains的设定对start_urls里的网址不会有影响。
    start_urls = []
    for x in range(3):
        url = 'https://book.douban.com/top250?start='+str(x*25)
        start_urls.append(url)
    # parse是Scrapy里默认处理response的一个方法
    def parse(self, response):
        bs = bs4.BeautifulSoup(response.text, 'html.parser')
        datas = bs.find_all('tr', class_='item')
        for data in datas:
            item = DoubanItem()
            item['title'] = data.find_all('a')[1]['title']
            item['publish'] = data.find('p', class_="pl").text
            item['score'] = data.find('span', class_="rating_nums").text
            print(item)
            yield item  # 类似于return, 但是不会结束函数
复制代码
猫哥教你写爬虫 047--scrapy框架
猫哥教你写爬虫 047--scrapy框架

代码实操——设置

我们需要修改请求头...

猫哥教你写爬虫 047--scrapy框架

ROBOTSTXT_OBEY=True 改成 ROBOTSTXT_OBEY=False ,就是把遵守robots协议换成无需遵从robots协议,这样Scrapy就能不受限制地运行。

猫哥教你写爬虫 047--scrapy框架

代码实操——运行

方法一: scrapy crawl douban(douban是我们爬虫的名字)

E:\helloSpider\douban> scrapy crawl douban

如果遇到...No module named win32api...

pip install pywin32

猫哥教你写爬虫 047--scrapy框架

方法二: main.py

猫哥教你写爬虫 047--scrapy框架

在最外层的大文件夹里新建一个main.py文件(与scrapy.cfg同级)

# 导入cmdline模块,可以实现控制终端命令行
from scrapy import cmdline
# 执行命令 "scrapy crawl douban"
cmdline.execute(['scrapy', 'crawl', 'douban'])
复制代码
猫哥教你写爬虫 047--scrapy框架

了教学方便理解,先写了爬虫,再定义数据。但是,在实际项目实战中,常常顺序却是相反的——先定义数据,再写爬虫。所以,流程图应如下:

猫哥教你写爬虫 047--scrapy框架

细心的你可能会发现,这一关的内容没有涉及到存储数据的步骤。

复习

猫哥教你写爬虫 047--scrapy框架
猫哥教你写爬虫 047--scrapy框架
猫哥教你写爬虫 047--scrapy框架

存储到mysql

存储数据需要修改pipelines.py文件, 不过我们需要先建立一个数据库

drop database if exists douban;
create database douban character set utf8;
use douban;
create table book(
	id int primary key auto_increment,
    title varchar(255) not null,
    publish varchar(255) not null,
    score decimal(2,1) not null
);
复制代码
mysql> desc book;
+---------+--------------+------+-----+---------+----------------+
| Field   | Type         | Null | Key | Default | Extra          |
+---------+--------------+------+-----+---------+----------------+
| id      | int(11)      | NO   | PRI | NULL    | auto_increment |
| title   | varchar(255) | NO   |     | NULL    |                |
| publish | varchar(255) | NO   |     | NULL    |                |
| score   | decimal(2,1) | NO   |     | NULL    |                |
+---------+--------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)
复制代码

有了数据库, 我们开始写 E:\helloSpider\douban\douban\pipelines.py

# -*- coding: utf-8 -*-
import pymysql
class DoubanPipeline(object):
    def __init__(self):
        # 创建数据库连接
        self.connection = pymysql.connect(
            host='localhost',
            port=3306,
            user='root',
            password='root',
            db='douban',
            charset='utf8'
        )
        self.cursor = self.connection.cursor()
    def process_item(self, item, third):
        # 拼接 sql 语句
        sql = "insert into book(title,publish,score) values({},{},{})".format(
            repr(item['title']), repr(item['publish']), item['score'])
        # 执行sql语句
        self.cursor.execute(sql)
        self.connection.commit()
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Designing Data-Intensive Applications

Designing Data-Intensive Applications

Martin Kleppmann / O'Reilly Media / 2017-4-2 / USD 44.99

Data is at the center of many challenges in system design today. Difficult issues need to be figured out, such as scalability, consistency, reliability, efficiency, and maintainability. In addition, w......一起来看看 《Designing Data-Intensive Applications》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具