利用Scrapy爬取豆瓣图书并保存至Mysql数据库

Scrapy是一个纯Python语言写的爬虫框架,本次用它来爬取豆瓣图书的数据。

准备工作

没有安装Scrapy的同学需要安装一下,有两种方式安装:

  • 安装了Anaconda的同学直接在命令行输入conda install scrapy,片刻后即可安装完成,这也是Scrapy官方推荐的安装方式
  • 安装了 pip 的同学,在命令行输入pip install scrapy,不过根据操作系统的不同,可能需要先安装别的依赖。

安装完成后,把命令行切换到自己的工作目录,新建一个Scrapy工程:
直接在命令行输入scrapy startproject douban

注释: Scrapy安装完成后,自带了一些操作命令

Scrapy框架会在当前目录下生成一个 douban 目录,并生成一些代码模板

douban目录下的内容

douban/douban 下面是代码放置的地方,douban/scrapy.cfg 是 Scrapy 的一些配置

构建要爬取的数据项

首先来看一下我们要爬取的网站 豆瓣图书

豆瓣图书

可以看到,每本书的属性有:书名,作者,类别,评分,评价人数,图书介绍。

将命令行切换至 douban 目录:cd douban

然后输入 scrapy genspider doubanspider https://read.douban.com/

框架会自动在 spiders 目录下生成一个 doubanspider.py,这就是爬虫的代码模板,我们等一下再来修改,先来创建一下我们要爬取的数据项。

编辑 items.py 如下

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class DoubanItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    book_name = scrapy.Field()          # 书名
    author = scrapy.Field()             # 作者
    class_ = scrapy.Field()             # 类别
    grade = scrapy.Field()              # 评分
    count = scrapy.Field()              # 人数
    introduction = scrapy.Field()       # 介绍

注释:class_字段有一个下划线是因为要与 python 里的关键字 class 区分开

网站结构分析

不同的网站有不同的结构,我们的爬虫要爬取哪个网站,就要先分析一下对应的网站结构。看一下豆瓣图书的网站结构,在浏览器中按下 F12 打开开发者工具。

可以看到,每本图书的信息都保存在一个 class="info" 的 div 里面,其对应的 xpath 路径为 "//div[@class="info"]"

豆瓣图书网站构成

书名在 class="title" 的 div 下面的一个 <a> 标签里面,其对应的 xpath 路径为 ".//div[@class="title"]/a/text()"

书名

作者在 class="labeled-text" 的 span 下面的一个 <a> 标签里面,其对应的
xpath 路径为 ".//span[@class="labeled-text"]/a/text()"

作者

类别在 itemprop="genre" 的一个 span 里面,其对应的 xpath 路径为 ".//span[@itemprop="genre"]/text()"

类别

评分在 class="rating-average" 的一个 span 里面,其对应的 xpath 路径为".//span[@class="rating-average"]/text()"

评分

评价人数在 class="ratings-link" 的 a 下面的一个 <span> 标签里面,其对应的 xpath 路径为 ".//a[@class="ratings-link"]/span/text()"

评价人数

图书介绍在 class="article-desc-brief" 的一个 div 里面,其对应的 xpath 路径为 ".//div[@class="article-desc-brief"]/text()"

图书介绍

下一页的链接在 class="next" 的 li 下面的一个 <a> 标签里面的 href 属性里面,其对应的 xpath 路径为 "//li[@class="next"]/a/@href"

后页

注释:XPath 是一门在 XML 文档中查找信息的语言,在这里查看XPath的语法

开始写爬虫

修改 doubanspider.py 如下:

# -*- coding: utf-8 -*-
import scrapy
from douban.items import DoubanItem                         # 导入要爬取的数据项

class DoubanspiderSpider(scrapy.Spider):
    name = 'doubanspider'
    allowed_domains = ['read.douban.com']
    # start_urls = ['http://read.douban.com/']

    def start_requests(self):                               # 构建Start_Request
        url = "https://read.douban.com/kind/114"
        yield scrapy.Request(url, callback=self.parse)

    def parse(self, response):                              # 爬取网站得到response后,自动回调parse方法
        item = DoubanItem()

        info_list = response.xpath('//div[@class="info"]')
        print(info_list)

        for info in info_list:
            item['book_name'] = info.xpath('.//div[@class="title"]/a/text()').extract_first()
            item['author'] = info.xpath('.//span[@class="labeled-text"]/a/text()').extract_first()
            item['class_'] = info.xpath('.//span[@itemprop="genre"]/text()').extract_first()
            item['grade'] = info.xpath('.//span[@class="rating-average"]/text()').extract_first()
            item['count'] = info.xpath('.//a[@class="ratings-link"]/span/text()').extract_first()
            item['introduction'] = info.xpath('.//div[@class="article-desc-brief"]/text()').extract_first()
            yield item

        next_temp_url = response.xpath('//li[@class="next"]/a/@href').extract_first()
        if next_temp_url is not None:
            next_url = response.urljoin(next_temp_url)
            yield scrapy.Request(next_url)

为了防止网站禁止爬虫,我们需要修改一下 settings.py 里的几项:

# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36'

上面的 User-Agent 引用自我的 chrome 浏览器,根据需要改成自己的

User-Agent

接下来我们测试一下爬虫能不能正常运行:
在命令行输入 scrapy crawl doubanspider -o doubanread.csv

不出错的话,会在命令行打印出我们爬取的每个数据项,然后保存到
doubanread.csv 文件里


doubanread.csv

注释:这里生成的csv文件用Excel直接打开会发现乱码,具体解决办法我还没找到,这里使用notepad++打开。
更新:经 你的发圈 提醒,使用sublime text 打开 CSV 文件,然后另存为 utf8 with bom 的格式,可解决 excel 打开乱码问题。

将数据保存到Mysql数据库

首先新建数据库,我在 bistu 数据库下新建了一个 doubanread 表

数据库建立

对应的 SQL 如下:

/*
Navicat MySQL Data Transfer

Source Server         : localhost
Source Server Version : 50717
Source Host           : localhost:3306
Source Database       : bistu

Target Server Type    : MYSQL
Target Server Version : 50717
File Encoding         : 65001

Date: 2017-10-22 16:47:44
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for doubanread
-- ----------------------------
DROP TABLE IF EXISTS `doubanread`;
CREATE TABLE `doubanread` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `book_name` varchar(255) DEFAULT NULL,
  `author` varchar(255) DEFAULT NULL,
  `class_` varchar(255) DEFAULT NULL,
  `grade` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT NULL,
  `introduction` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1409 DEFAULT CHARSET=utf8;

然后修改 pipelines.py 文件:

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import pymysql as pq                # 导入pymysql


class DoubanPipeline(object):
    def __init__(self):
        self.conn = pq.connect(host='localhost', user='root',
                               passwd='123456', db='bistu', charset='utf8')
        self.cur = self.conn.cursor()

    def process_item(self, item, spider):
        book_name = item.get("book_name", "N/A")    # 有的图书有数据项缺失,这里做了容错处理
        author = item.get("author", "N/A")
        class_ = item.get("class_", "N/A")
        grade = item.get("grade", "N/A")
        count = item.get("count", "N/A")
        introduction = item.get("introduction", "N/A")

        sql = "insert into doubanread(book_name, author, class_, grade, count, introduction) VALUES (%s, %s, %s, %s, %s, %s)"
        self.cur.execute(sql, (book_name, author, class_, grade, count, introduction))
        self.conn.commit()
    
    def close_spider(self, spider):
        self.cur.close()
        self.conn.close()

注释:你没有猜错, pipelines.py 就是 scrapy 框架用来与数据库交互的地方,在此之前,我们需要安装 pysql ,安装方法与 scrapy 的安装方法一样:conda install scrapypip install scrapy

只修改了 pipelines.py 还不行,我们还需要修改一个文件,就是之前的 settings.py 文件,找到这里,,将注释取消掉:

# Configure item pipelines
# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'douban.pipelines.DoubanPipeline': 300,
}

最后在命令行里输入 scrapy crawl doubanspider 运行项目。

查看数据库,可以看到我们爬取的数据,缺失的数据项补为了Null

爬取到的数据
Game Over
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容