学习scrapy框架爬小说
一、背景:近期学习python爬虫技术,感觉挺有趣。由于手动自制爬虫感觉效率低,了解到爬虫界有先进的工具可用,尝试学学scrapy爬虫框架的使用。
二、环境:centos7,python3.7,scrapy1.7.3
三、scrapy原理简述:
1、scrapy框架组成:引擎、调度器、下载器(含下载器中间件)、爬虫组件(spider,含爬虫中间件)、输出管道(item pipelines)
2、scrapy工作过程:
(1)引擎发起爬虫请求,提交给调度器安排任务排序。
(2)调度器安排的下载任务通过引擎提交下载器开展下载任务(发出Quests请求)。
(3)下载器获得的Response通过引擎回到爬虫组件进行内容爬取的处理。(这一步就是人为工作的重点,爬取什么内容,如何爬取等设计需要人为设定控制。)
(4)爬虫组件处理后的数据通过item pipelines组件进行输出,可输出为json、数据库、csv等等格式。(这一步需要根据具体需求,可人为控制输出方案。)
(5)上述过程循环往复,直到预定爬取任务完成。
四、scrapy工程构建过程(以爬取新笔趣阁网站www.xbiquge.com上的《汉乡》小说为例)
1、新建爬虫工程
(base) [python@ELK ~]$ scrapy startproject hanxiang
New Scrapy project 'hanxiang', using template directory '/home/python/miniconda3/lib/python3.7/site-packages/scrapy/templates/project', created in:
/home/python/hanxiang
You can start your first spider with:
cd hanxiang
scrapy genspider example example.com
工程目录结构:
(base) [python@ELK ~]$ tree hanxiang
hanxiang
├── hanxiang
│ ├── __init__.py
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── __pycache__
│ ├── settings.py
│ └── spiders
│ ├── __init__.py
│ └── __pycache__
└── scrapy.cfg
2、进入爬虫工程目录并生成爬虫程序文件
(base) [python@ELK ~]$ cd hanxiang
(base) [python@ELK hanxiang]$ scrapy genspider Hanxiang www.xbiquge.la/15/15158 #注意,爬虫名称不能与工程名称重名;链接不要加http://或https://关键字,链接尾部不要有/符号。
Created spider 'Hanxiang' using template 'basic' in module:
hanxiang.spiders.Hanxiang
(base) [python@ELK hanxiang]$ tree
.
├── hanxiang
│ ├── __init__.py
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── __pycache__
│ │ ├── __init__.cpython-37.pyc
│ │ └── settings.cpython-37.pyc
│ ├── settings.py
│ └── spiders
│ ├── Hanxiang.py
│ ├── __init__.py
│ └── __pycache__
│ └── __init__.cpython-37.pyc
└── scrapy.cfg
在爬虫工程中新生成的文件中,重点是Hanxiang.py的爬虫程序文件。
3、编制爬虫文件和相关的配置文件
(1)修改settings.py文件
(base) [python@ELK hanxiang]$ vi hanxiang/settings.py
# -*- coding: utf-8 -*-
# Scrapy settings for hanxiang project
BOT_NAME = 'hanxiang'
SPIDER_MODULES = ['hanxiang.spiders']
NEWSPIDER_MODULE = 'hanxiang.spiders'
ROBOTSTXT_OBEY = False #爬取不受网站限制
...
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'hanxiang.pipelines.HanxiangPipeline': 300, #启用pipelines功能,300是优先级配置,其取值范围0-1000
}
...
FEED_EXPORT_ENCODING = 'utf-8' #输出编码设置
(2)修改items.py配置(确定需要爬取的内容)
(base) [python@ELK hanxiang]$ vi hanxiang/items.py
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class HanxiangItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
url = scrapy.Field() #需要获取小说的章节链接
preview_page = scrapy.Field() #小说的上一页章节链接
next_page = scrapy.Field() #小说的下一页章节链接
content = scrapy.Field() #小说的章节内容
(3)编制pipelines.py程序,控制输出内容。(目标:把爬取的四个字段内容输出到mysql数据库,以方便后续处理。)
(base) [python@ELK hanxiang]$ vi hanxiang/pipelines.py
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
import os
import pymysql
from twisted.enterprise import adbapi
from pymysql import cursors
class HanxiangPipeline(object): #类名是自动生成的,不用更改。
def __init__(self): #定义类初始化动作,包括连接数据库novels和创建hanxiang数据表。
dbparams = {
'host': '127.0.0.1',
'port': 3306,
'user': 'root',
'password': 'password',
'database': 'novels',
'charset': 'utf8'
}
self.conn = pymysql.connect(**dbparams)
self.cursor = self.conn.cursor()
self._sql = None
#建表
def createtable(self):
self.cursor.execute("drop table if exists hanxiang")
self.cursor.execute("create table hanxiang (id int unsigned auto_increment not null primary key, url varchar(50) not null, preview_page varchar(50), next_page varchar(50), content TEXT not null) charset=utf8")
return
#爬取内容写入数据表
def process_item(self, item, spider): #此方法名字也是自动生成,不能更改。
self.cursor.execute(self.sql, (item['url'], item['preview_page'], item['next_page'], item['content'])) #执行sql命令,向hanxiang数据表写入爬取的数据。
self.conn.commit() #需执行commit,数据表内容才会更新。
return item
@property
def sql(self):
if not self._sql:
self._sql = """
insert into hanxiang(id, url, preview_page, next_page, content) values(null, %s, %s, %s, %s)
"""
return self._sql
return self._sql
#从数据库取小说章节内容写入txt文件
def content2txt(self):
self.cursor.execute("select count(*) from hanxiang")
record_num = self.cursor.fetchall()[0][0] #取数据表的总记录数,注意fetchall反馈的是元组
#counts=5 #测试用
counts=record_num
url_c = "\"" + "http://www.xbiquge.la/15/15158/6873206.html" + "\"" #第一章的链接变量,需要注意带上双引号,以便提供给sql查询
start_time=time.time() #获取提取小说内容程序运行的起始时间
f = open("汉乡.txt", mode='w', encoding='utf-8')
for i in range(counts):
sql_c = "select content from hanxiang where url=" + url_c #组合获取小说章节内容的sql命令
self.cursor.execute(sql_c)
record_content_c2a0=self.cursor.fetchall()[0][0] #获取小说章节内容
record_content=record_content_c2a0.replace(u'\xa0', u'') #消除特殊字符\xc2\xa0
#print(record_content)
f.write('\n')
f.write(record_content + '\n')
f.write('\n\n')
sql_n = "select next_page from hanxiang where url=" + url_c #组合获取下一章链接的sql命令
self.cursor.execute(sql_n)
url_c = "\"" + self.cursor.fetchall()[0][0] + "\"" #下一章链接地址赋值给url_c,准备下一次循环。
#print(record_content[0][0])
f.close()
print(time.time()-start_time)
return
#爬虫结束,调用content2txt方法,生成txt文件
def close_spider(self,spider):
self.content2txt()
return
(4)编制爬虫主程序Hanxiang.py,爬取设定内容。
(base) [python@ELK hanxiang]$ vi hanxiang/spiders/Hanxiang.py
# -*- coding: utf-8 -*-
import scrapy
from hanxiang.items import HanxiangItem
class HanxiangSpider(scrapy.Spider): #自动生成的爬虫类名
name = 'Hanxiang'
#allowed_domains = ['www.xbiquge.la/15/15158'] #自动生成的爬取页面控制范围(域)
allowed_domains = ['xbiquge.la'] #放宽爬取页面限制,否则,就需要在更深一级发出的Request方法中使用dont_filter=True参数。
def start_requests(self): #方法名称不能变
start_urls = ['http://www.xbiquge.la/15/15158/'] #启动爬取页面应以list方式存放,变量名称不能改变。
for url in start_urls:
yield scrapy.Request(url=url, callback=self.parse) #生成器模式(yield)调用爬虫处理方法parse,效率很高。
def parse(self, response): #方法名称不能变
dl = response.css('#list dl dd') #提取章节链接相关信息
for dd in dl:
self.url_c = "http://www.xbiquge.la" + dd.css('a::attr(href)').extract()[0] #组合形成小说的各章节链接
#print(self.url_c)
#yield scrapy.Request(self.url_c, callback=self.parse_c,dont_filter=True )
yield scrapy.Request(self.url_c, callback=self.parse_c) #以生成器模式(yield)调用parse_c方法获得各章节链接、上一页链接、下一页链接和章节内容信息。
#print(self.url_c)
def parse_c(self, response):
item = HanxiangItem()
item['url'] = response.url
item['preview_page'] = "http://www.xbiquge.la" + response.css('div .bottem1 a::attr(href)').extract()[1]
item['next_page'] = "http://www.xbiquge.la" + response.css('div .bottem1 a::attr(href)').extract()[3]
title = response.css('.con_top::text').extract()[4]
contents = response.css('#content::text').extract()
text=''
for content in contents:
text = text + content
#print(text)
item['content'] = title + "\n" + text.replace('\15', '\n') #各章节标题和内容组合成content数据,\15是^M的八进制表示,需要替换为换行符。
yield item #以生成器模式(yield)输出Item对象的内容给pipelines模块。
(5)编制mysql数据库建表程序()
(base) [python@ELK hanxiang]$ vi createtable.py
# -*-coding:utf-8-*-
from hanxiang.pipelines import HanxiangPipeline
HanxiangPipeline().createtable()
(6)编制txt文件生成程序(此程序可手工运行单独生成txt文件)
(base) [python@ELK hanxiang]$ vi spider2txt.py
# -*- coding:utf-8 -*-
#调用pipelines.py中模块HanxiangPipeline的content2txt方法,生成txt文件
from hanxiang.pipelines import HanxiangPipeline
HanxiangPipeline().content2txt()
4、运行爬虫:
(1)运行建表程序(生成mysql数据表)
(base) [python@ELK hanxiang]$ python createtable.py
(2)运行爬虫主程序(爬取数据写入mysql数据库,并在爬虫结束时,从数据库提取数据按章节顺序生成txt文件。)
(base) [python@ELK hanxiang]$ scrapy runspider hanxiang/spiders/Hanxiang.py
5、运行结果显示
...
'next_page': 'http://www.xbiquge.la/15/15158/6873262.html',
'preview_page': 'http://www.xbiquge.la/15/15158/6873260.html',
'url': 'http://www.xbiquge.la/15/15158/6873261.html'}
2019-08-24 23:50:22 [scrapy.core.engine] INFO: Closing spider (finished)
7.578139305114746
2019-08-24 23:50:30 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 412373,
'downloader/request_count': 1492,
'downloader/request_method_count/GET': 1492,
'downloader/response_bytes': 10242909,
'downloader/response_count': 1492,
'downloader/response_status_count/200': 1492,
'elapsed_time_seconds': 170.554676,
'finish_reason': 'finished',
'finish_time': datetime.datetime(2019, 8, 24, 15, 50, 30, 547474),
'item_scraped_count': 1491,
'log_count/DEBUG': 2983,
'log_count/INFO': 12,
'log_count/WARNING': 1,
'memusage/max': 70201344,
'memusage/startup': 44478464,
'request_depth_max': 1,
'response_received_count': 1492,
'scheduler/dequeued': 1492,
'scheduler/dequeued/memory': 1492,
'scheduler/enqueued': 1492,
'scheduler/enqueued/memory': 1492,
'start_time': datetime.datetime(2019, 8, 24, 15, 47, 39, 992798)}
2019-08-24 23:50:30 [scrapy.core.engine] INFO: Spider closed (finished)
(base) [python@ELK hanxiang]$ ll
...
-rw-rw-r--. 1 python python 11889462 8月 24 23:50 汉乡.txt
学习scrapy框架爬小说的更多相关文章
- 《学习scrapy框架爬小说》的进一步完善
一.完善目标: 1.为方便使用,把小说拼音或英文名,小说输出中文名,第一章节url地址变量化,修改这些参数即可爬取不同的小说. 2.修改settings.py设置文件,配置为记录debug的log信息 ...
- Python多线程爬图&Scrapy框架爬图
一.背景 对于日常Python爬虫由于效率问题,本次测试使用多线程和Scrapy框架来实现抓取斗图啦表情.由于IO操作不使用CPU,对于IO密集(磁盘IO/网络IO/人机交互IO)型适合用多线程,对于 ...
- 使用scrapy框架爬取自己的博文(2)
之前写了一篇用scrapy框架爬取自己博文的博客,后来发现对于中文的处理一直有问题- - 显示的时候 [u'python\u4e0b\u722c\u67d0\u4e2a\u7f51\u9875\u76 ...
- 爬虫入门(四)——Scrapy框架入门:使用Scrapy框架爬取全书网小说数据
为了入门scrapy框架,昨天写了一个爬取静态小说网站的小程序 下面我们尝试爬取全书网中网游动漫类小说的书籍信息. 一.准备阶段 明确一下爬虫页面分析的思路: 对于书籍列表页:我们需要知道打开单本书籍 ...
- Python使用Scrapy框架爬取数据存入CSV文件(Python爬虫实战4)
1. Scrapy框架 Scrapy是python下实现爬虫功能的框架,能够将数据解析.数据处理.数据存储合为一体功能的爬虫框架. 2. Scrapy安装 1. 安装依赖包 yum install g ...
- 使用scrapy框架爬取自己的博文(3)
既然如此,何不再抓一抓网页的文字内容呢? 谷歌浏览器有个审查元素的功能,就是按树的结构查看html的组织形式,如图: 这样已经比较明显了,博客的正文内容主要在div 的class = cnblogs_ ...
- 使用scrapy框架爬取自己的博文
scrapy框架是个比较简单易用基于python的爬虫框架,http://scrapy-chs.readthedocs.org/zh_CN/latest/ 这个是不错的中文文档 几个比较重要的部分: ...
- Python学习---爬虫学习[scrapy框架初识]
Scrapy Scrapy是一个框架,可以帮助我们进行创建项目,运行项目,可以帮我们下载,解析网页,同时支持cookies和自定义其他功能. Scrapy是一个为了爬取网站数据,提取结构性数据而编写的 ...
- 基于python的scrapy框架爬取豆瓣电影及其可视化
1.Scrapy框架介绍 主要介绍,spiders,engine,scheduler,downloader,Item pipeline scrapy常见命令如下: 对应在scrapy文件中有,自己增加 ...
随机推荐
- Java——Java自动装箱和拆箱
一.什么是自动装箱和拆箱: 我们知道java为8种基本类型分别提供了对应的包装类型,在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行: Integer i=new I ...
- 龟兔赛跑算法 floyed判环算法
今天写线段树写到要用到这个算法的题目,简单的学习一下. https://blog.csdn.net/javaisnotgood/article/details/89243876 https://blo ...
- spring mvc从后台往前台传参数的三种方式
第一种:使用Model对象(常用) 第一步:使用model对象往前台传递数据 第二步:在jsp中接收从后台传递过来的参数 第二种:使用HttpServletRequest对象 第一步:使用HttpSe ...
- python学习之if条件句的使用
if循环 if 条件: 代码块 运行 if else的用法 if elseif else用法 if 条件1: elif 条件2: elif条件3: else:
- 【GISER&&规划】我这二三年
从从参加工作到现在,已经接近三年了.在这不长不短的时间里,我的职业规划犹如正余弦函数一样变化,一直游离在前端和后端之间. 第一年入职,被安排维护和拓展一套基于JAVA实现的地图瓦片生产工艺程序,不算复 ...
- Liunx常用操作(五)-如何查询文档中的冒号与引号
liunx下面有如下一段包含json格式的文档 一.单查所有冒号: .txt | grep [:] 结果如下: 二.单查所有引号: 这里需要转义 .txt | grep [\"] 三.gre ...
- 基于mykernel 2.0编写一个操作系统内核
一.配置mykernel 2.0,熟悉Linux内核的编译 1.实验环境:VMware 15 Pro,Ubuntu 18.04.4 2.配置环境 1)在电脑上先下载好以下两个文件,之后通过共享文件夹, ...
- Android广播机制(1)
目录 简介 发送广播和接收广播方式 广播类型 接收系统广播 动态注册监听网络变化 步骤 优化 静态注册实现开机启动 步骤 注意 简介 就是因为安卓中的每个应用程序都可以对自己感兴趣的广播进行注册,这样 ...
- 关于日常操作中sql的性能
最近接手了一个项目.使用的数据库是sql server,但是遇到一些关于日期的查询的时候,查询结果非常慢.看了下别人的sql //sql = sql + " and CONVERT(nvar ...
- Unity直接调用Android Toast
Unity直接调用Android Toast 这两天在搭一套UI框架,想把Android的Toast直接集成上去,有不想直接打jar包,所有写了个C#直接调用,废话不多说,直接干货: using Un ...