之前也没有认真写过爬虫项目,这应该算我第一个比较正式的爬虫项目。主要的目的就是练习一下scrapy框架。一个高效强大的爬虫框架。文档在这里
这个爬虫的目的是抓取笔趣阁(因为是盗版网站,链接可能失效)上所有的小说。
首先安装scrapy
我使用的是windows,python版本是3.5,在安装的时候报错,因为缺少vc的支持库,不能编译c的代码,可以通过去微软官方下载vc++ build tool解决。
创建项目
1
| scrapy startproject biquge
|
成功之后的目录结构:
因为scrapy默认是不能在cmd下进行调试的,我们建立一个入口文件,使他能够在cmd中调试,在工程根目录下建立start.py
1 2
| from scrapy.cmdline import execute execute(['scrapy', 'crawl', 'biquge'])
|
为了减轻网站的压力,也为了调试迅速,启动缓存。去掉setting.py中最后几行的注释
1 2 3 4 5
| HTTPCACHE_ENABLED = True HTTPCACHE_EXPIRATION_SECS = 0 HTTPCACHE_DIR = 'httpcache' HTTPCACHE_IGNORE_HTTP_CODES = [] HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
|
准备工作就绪,下面开始写爬虫程序。
首先抓取基本的信息,小说的名字,id,作者。
定义字段
在item.py中写入下面的代码
1 2 3 4 5 6 7 8 9 10 11 12
| class BiqugeItem(scrapy.Item): # id novel_id = scrapy.Field() # 小说名字 name = scrapy.Field() # 小说作者 author = scrapy.Field() # 小说url url = scrapy.Field() # 小说简介 content = scrapy.Field()
|
编写spider
在spiders文件夹下新建,biqugespider.py,定义爬虫入口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import scrapy from scrapy.http import Request from biquge.items import BiqugeItem import re class BiqugeSpider(scrapy.Spider): # 爬虫的名字,和start.py中相对应。 name = 'biquge' base_url = 'http://www.qu.la' # 爬虫入口 def start_requests(self): start_url = self.base_url + '/xiaoshuodaquan/' yield Request(start_url, callback=self.get_novel_url)
|
scrapy的Request()会把response自动返回callback的函数。
定义 get_novel_url
1 2 3 4 5 6
| # 获取小说url def get_novel_url(self, response): base_a = response.xpath('//div[@class="novellist"]/ul/li/a/@href').extract() for a in base_a: novel_a = self.base_url + a yield Request(novel_a, callback=self.get_information_and_chapter, meta={"novel_a": novel_a})
|
可以使用meta参数进行传值,把meta中的结果传到,回掉函数的response中,使用response.meta[‘name’]取值。
接下来获取小说的基本信息。并存在item中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| # 获取基本信息 def get_information_and_chapter(self, response): item = BiqugeItem() item['content'] = ''.join(response.xpath('//meta[@property="og:description"]/@content').extract()). \ replace(' ', ''). \ replace('\n', '') # 保存小说链接 novel_url = response.meta['novel_a'] item['url'] = novel_url # 提取小说名字 novel_name = ''.join(response.xpath('//meta[@property="og:novel:book_name"]/@content').extract()) item['name'] = novel_name # 提取小说作者 item['author'] = ''.join(response.xpath('//meta[@property="og:novel:author"]/@content').extract()) # 从url中提取小说id novel_id = ''.join(re.findall('\d', novel_url)) item['novel_id'] = novel_id yield item
|
我使用mysql来进行存取数据,先建一张表,存小说的基本信息。
1
| CREATE TABLE `novel`.`biquge_information` ( `id` INT NOT NULL AUTO_INCREMENT , `novel_id` VARCHAR(255) NOT NULL , `author` VARCHAR(255) NOT NULL , `url` VARCHAR(255) NOT NULL , `novel_name` VARCHAR(255) NOT NULL , `content` VARCHAR(255) NOT NULL , PRIMARY KEY (`id`)) ENGINE = InnoDB;
|
在目录下新建一个包mysqlpipelines 在下面新建 init.py pipelines.py sql.py
需要安装mysql-connector
1
| pip install mysql-connector
|
在setting.py中设置mysql的基本信息。
1 2 3 4 5
| MYSQL_HOST = '127.0.0.1' MYSQL_USER = 'root' MYSQL_PASSWORD = '' MYSQL_PORT = '3306' MYSQL_DB = 'novel'
|
初始一个mysql游标,并且定义两个方法,其中一个用于插入数据,另外一个用于判断数据是否存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import mysql.connector from biquge import settings cnx = mysql.connector.connect(user=settings.MYSQL_USER, password=settings.MYSQL_PASSWORD, host=settings.MYSQL_HOST, database=settings.MYSQL_DB) cur = cnx.cursor(buffered=True) class Sql: @classmethod def insert_infor(cls, novel_id, author, name, url, content): sql = 'INSERT INTO `biquge_information` (`novel_id`, `novel_name`, `author`, `url`, `content`) ' \ 'VALUES (%(novel_id)s, %(novel_name)s, %(author)s, %(url)s, %(content)s)' value = { 'novel_id': novel_id, 'novel_name': name, 'author': author, 'url': url, 'content': content } cur.execute(sql, value) cnx.commit() @classmethod def select_novel_id(cls, novel_id): sql = 'SELECT EXISTS(SELECT 1 FROM biquge_information WHERE novel_id=%(novel_id)s)' value = { 'novel_id': novel_id } cur.execute(sql, value) return cur.fetchall()[0]
|
编写pipelines.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from .sql import Sql from biquge.items import BiqugeItem from biquge.items import ChapterContentItem class BiqugePipeline(object): def process_item(self, item, spider): if isinstance(item, BiqugeItem): novel_id = item['novel_id'] ret = Sql.select_novel_id(novel_id) if ret[0] == 1: print('小说已经存在') pass else: name = item['name'] author = item['author'] content = item['content'] url = item['url'] print('小说不存在') Sql.insert_infor(novel_id, author, name, url, content)
|
运行start.py,爬虫就可以抓取笔趣阁上所有小说的基本信息了。
当然也可以抓取小说章节内容,可是懒癌犯了,就不写了,详见完整项目