爬虫-豆瓣书籍排行榜及用户信息-2021.7.23-使用Scrapy框架-用MongoDB存储数据
1.环境
python3.8或python3.7
pycharm2021.2
MongoDB
Scrapy
2.信息提取
2.1 创建Scrapy项目
在cmd模式下创建Scrapy项目
# 进入要存放该项目的文件夹下
cd E:\Scrapy Project
# 创建Scrapy项目
scrapy startproject douban
# 进入该项目下,“douban”这个文件夹有一个一级文件夹和二级文件夹,我们只用进入一级文件夹
cd douban
# 创建Spider
scrapy genspider douban_book douban.com
2.2 在Pycharm中打开该项目
打开后,文件树结构为:
注意scrapy.cfg配置文件一定在“douban”一级文件夹下,不然在后面运行该爬虫时,会报错。
2.3 项目目标
1.获取按评分排行的书籍排行榜前任意页的书籍基本信息
2.获取每本书籍的读者评论信息和读者主页链接
3.获取读者的地址
4.写入MongoDB数据库
2.4 初始化数据
初始化rank_url、book_comment_url、headers、allowed_domain等信息,其中name是不能修改的。
刚打开douban_book.py,是如下图所示的界面。
然后修改上述信息。如下图所示。
其中allowed_domain一般情况下不用修改,我这里是测试的时候,发现访问书籍链接地址的时候,其域名是“book.douban.com”,所以添加了进去,其实还有另一种方法,就是在Request函数(很关键的函数)中把域名过滤给关闭掉。
start_urls是在你没有指定访问链接的时候,默认的访问链接,如果有就不会访问该链接。
这里我们有访问的链接,所以我们把start_urls删除了,写上了自己要访问的rank_url,也就是书籍排行榜的访问链接地址,这里有四个,是不同分类的书籍排行榜,分别是文化分类下的“历史”,“哲学”等几个标签,当然也可以继续增加其他访问链接地址。
但是这个链接地址需要进行预处理,也就是如下图勾画的地方
我们先找到按评分排行的书籍排行榜第二页(因为第一页一般看不出规律)。如下图
然后再到第三页,可以看到start=后面的数字在不断变化,其他都没有变化。
上述写成start={start_rank}是因为字符串的format()方法可以填充该值。
其中book_comments_url也是用相似的方法找到规律后进行的预处理。
2.5 访问书籍排行榜
def start_requests(self):for url in self.rank_url:for page in range(0, 30):start_rank = page * 20yield Request(url.format(start_rank=start_rank), headers=self.headers,callback=self.parse_to_books)
其中Request方法表示使用headers去访问url,返回的信息用callback中的方法进行处理。
2.6 对书籍排行榜的信息进行处理——xpath方法
def parse_to_books(self, response):# 从html信息中可以看到每本书籍的基本信息都在单独的subject-item,所以先找到所有的subject-itemresults = response.xpath('//li[@class="subject-item"]')# 然后遍历每个subject-item,这里用的results保存的所有subject-itemfor result in results:book_href = result.xpath('./div[@class="info"]/h2/a/@href')book_name = result.xpath('normalize-space(./div[@class="info"]/h2/a/@title)')book_pub = result.xpath('normalize-space(./div[@class="info"]/div[@class="pub"]/text())')book_score = result.xpath('./div[@class="info"]/div/span[@class="rating_nums"]/text()')book_population = result.xpath('normalize-space(./div[@class="info"]/div/span[@class="pl"]/text())')# 用创建BookItem()对象,用其保存书籍的基本信息item_book = BookItem()item_book['book_name'] = book_name.extract()item_book['book_href'] = book_href.extract()print(book_href.extract())# 这里获取book_id,用于访问书籍的评论列表book_id = str(item_book['book_href']).split('/')[-2]print(book_id)item_book['book_pub'] = book_pub.extract()item_book['book_score'] = book_score.extract()item_book['book_population'] = book_population.extract()# 然后遍历该书籍的评论列表前10页,在不登录的情况下,只能访问前10页内容。for page in range(0, 10):# 访问书籍评论列表链接,对返回的页面信息用parse_to_reader处理,meta表示传给parse_to_reader会用到的一些数据,是一个字典,可以根据需要继续添加一些数据。yield Request(self.book_comments_url.format(book_id=book_id, start_comments=page * 20),headers=self.headers,callback=self.parse_to_reader, meta={'book_href': book_href.extract()})yield item_book
2.6 和2.8节会用到BookItem()和ReaderItem_culture(),这几个数据结构在2.9中展示。
2.7 对书籍评论列表页面信息进行处理
这里获取了读者的主页链接、读者的评论,还有传入的meta,也就是书籍的链接,并将上述信息传入到parse_to_reader_address。
def parse_to_reader(self, response):results = response.xpath('//li[@class="comment-item"]')for result in results:reader_href = result.xpath('./div[@class="avatar"]/a/@href').extract()reader_comment = result.xpath('./div[@class="comment"]/p[@class="comment-content"]/span[''@class="short"]/text()').extract()book_href = response.meta['book_href']yield Request(str(reader_href).strip("['").strip("']"), headers=self.headers,callback=self.parse_to_reader_address,meta={'book_href': book_href, 'reader_href': reader_href,'reader_comment': reader_comment})
其基本原理和2.6节一样。这里就不一一赘述了。
2.8 对读者主页信息进行处理
这里获取了读者的地址信息,其基本原理和上述一样,并将信息传入ReaderItem_culture()对象。
def parse_to_reader_address(self, response):print("获取用户地址")book_href = str(response.meta['book_href']).strip("['").strip("']")reader_href = str(response.meta['reader_href']).strip("['").strip("']")reader_comment = str(response.meta['reader_comment'])reader_address_raw = response.xpath('normalize-space(//div[@class="basic-info"]/div[@class="user-info"]/a/text())').extract()reader_address = str(reader_address_raw).strip("['").strip("']")if reader_address.strip() == '':print("地址为空")returnitem_reader = ReaderItem_culture()item_reader['book_href'] = book_hrefitem_reader['reader_href'] = reader_hrefitem_reader['reader_comment'] = reader_commentitem_reader['reader_address'] = reader_addressyield item_reader
2.9 以上用到的Item对象
Item对象在Items.py中申明
import scrapy
class BookItem(scrapy.Item):collection = 'douban_books_culture'book_name = scrapy.Field()book_href = scrapy.Field()book_pub = scrapy.Field()book_score = scrapy.Field()book_population = scrapy.Field()class ReaderItem_culture(scrapy.Item):collection = 'douban_readers_culture'book_href = scrapy.Field()reader_href = scrapy.Field()reader_comment = scrapy.Field()reader_address = scrapy.Field()
其中collection表示的是MongoDB的集合名(类似于MySQL中的表名)。
2.10 小结
以上做了这几件事:
1.对豆瓣的书籍基本信息做了提取,并传入到了BookItem()对象。
2.对读者评论信息、主页链接、地址进行了提取,并传入到了ReaderItem_culture对象。
接下来需要将上述提取的信息存入到MongoDB中。
3.存入数据
存入数据的代码在pipeline.py中书写。
import pymongo
import loggingclass MongoPipeline(object):def __init__(self, mongo_uri, mongo_db):self.mongo_uri = mongo_uriself.mongo_db = mongo_db@classmethod# 这一步是从settings配置文件里面获取MONGO_URI、MONGO_DB两个自己设置的常量def from_crawler(cls, crawler):return cls(mongo_uri=crawler.settings.get('MONGO_URI'),mongo_db=crawler.settings.get('MONGO_DB'))# 这一步是连接MongoDB数据库def open_spider(self, spider):self.client = pymongo.MongoClient(self.mongo_uri)self.db = self.client[self.mongo_db]def process_item(self, item, spider):result = self.db[item.collection].find(item)logging.debug("*"*50)if result.count() == 0:logging.debug("### 无重复、插入数据 ###")self.db[item.collection].insert(dict(item))else:logging.debug("### 有重复、没有插入 ###")logging.debug("*"*50)return itemdef close_spider(self, spider):self.client.close()
4.反爬虫
豆瓣的反爬虫机制很简单,就是看你的访问频率,因此我们仅需要做一个随机延迟访问就可以绕过他的反爬虫机制。
随机延迟在middleware.py中书写。
import logging
import random
import timeclass RandomDelayMiddleware(object):def __init__(self, delay):self.delay = delay@classmethoddef from_crawler(cls, crawler):delay = crawler.spider.settings.get("RANDOM_DELAY", 10)if not isinstance(delay, int):raise ValueError("RANDOM_DELAY need a int")return cls(delay)def process_request(self, request, spider):delay = random.randint(1, self.delay)logging.debug("### random delay: %s s ###" % delay)time.sleep(delay)
5.其他设置
需要修改settings.py文件
还有添加数据库的用户名和密码以及随机延迟上限。
最后修改pipeline.py中的类的优先级以及middleware.py中类的优先级。数字越大,优先级越高。由于我们上述两个文件都分别只有一个类,所以下面配置的意思是先执行RandomDelayMiddleware,再执行MongoPipeline。
6.一些帮助理解的东西
6.1 Scrapy的编码流程
先写douban_book.py。这里是进行网页页面信息处理的,包括访问、信息提取等。
再写items.py,如果douban_book.py中需要用到item,就在这里写。
接着在middlewares.py中写访问延迟。
然后再pipeline.py中写对item的存储。
最后在settings.py中配置,包括关闭ROBOTSTXT_OBEY,一些上述文件用到的常量以及优先级设置。
6.2 Scrapy工作流程
这部分仅是个人理解,各取所需。
其实Scrapy项目的执行过程不仅限于我们的项目之下的文件,还有在Scrapy包中的文件。Scrapy项目由以下几个部分组成:Engine(引擎)、Item(项目)、Scheduler(调度器)、Downloader(下载器)、Spiders(蜘蛛)、Item Pipeline(项目管道)、Downloader Middlewares(下载器中间件)、Spider Middleware(蜘蛛中间件)。
其中
- Item就是items.py中的东西
- Spiders就是douban_book.py中的东西
- Downloader Middlewares一部分在Scrapy包中,一部分就是middlewares.py中的东西
- Item Pipeline就是pipelines.py中的东西。
其工作方式简单点理解就是如下:
- Engine从Spider,也就是douban_book.py开始执行,
- 然后Engine从Spider中获取了URL,然后将这些URL放入到了Scheduler调度器,通过Request方法调度。应该类似于操作系统里面的调度。
- 接着由调度器传URL给Engine,Engine让Downloader Middlewares处理后发送给Downloader进行下载,也就是页面信息等的下载,Downloader会生成该页面信息的Response,然后将Response通过Downloader Middlewares处理后返回给Spider。
- 然后Spider处理Response,提取Item,或者新的Request给Engine。
- 最后Engine将返回的Item给Item Pipeline,新的Request给Scheduler。
- 重复2-6。
Engine就相当于中介,负责Scheduler、Spider、Downloader、Item Pipeline的联系,然后Engine和Downloader联系过程中需要用到Downloader Middlewares进行处理。
爬虫-豆瓣书籍排行榜及用户信息-2021.7.23-使用Scrapy框架-用MongoDB存储数据相关推荐
- Python|并发编程|爬虫|单线程|多线程|异步I/O|360图片|Selenium及JavaScript|Scrapy框架|BOM 和 DOM 操作简介|语言基础50课:学习(12)
文章目录 系列目录 原项目地址 第37课:并发编程在爬虫中的应用 单线程版本 多线程版本 异步I/O版本 总结 第38课:抓取网页动态内容 Selenium 介绍 使用Selenium 加载页面 查找 ...
- Python爬虫爬取知乎用户信息+寻找潜在客户
[Python应用]寻找社交网络中的目标用户 日后的更新:由于是很久以前的课程设计项目,完整的源码已经不见了,关键的网页数据获取和解析的部分代码我在文章中已经贴出来了,但写的也不够好,如果想参考爬取知 ...
- python爬虫scrapy框架爬取网页数据_Scrapy-Python
scrapy Scrapy:Python的爬虫框架 实例Demo 抓取:汽车之家.瓜子.链家 等数据信息 版本+环境库 Python2.7 + Scrapy1.12 初窥Scrapy Scrapy是一 ...
- python3爬虫----人人贷散标用户信息爬取
前提 本文基于此篇博文的实现思路以及给出的代码.不得不说,此博主心真的细,这个数据隐藏点都找到了,从而使得此爬虫的实现简单许多. 但我在使用博主代码时,发现人人贷网站有些许改变,于是对应代码我也相应做 ...
- 搭建nuxtjs程序 —— 用户信息 or token怎么不丢失
框架背景:开发框架采用vue,需要更好的SEO,更快的内容到达时间,从浏览器看不到对服务器的请求接口,选用开箱即用的nuxtjs. 问题背景:1. 前后分离,需前端存储token及登录后的用户信息: ...
- python爬取豆瓣书籍_Python利用lxml模块爬取豆瓣读书排行榜的方法与分析
前言 上次使用了BeautifulSoup库爬取电影排行榜,爬取相对来说有点麻烦,爬取的速度也较慢.本次使用的lxml库,我个人是最喜欢的,爬取的语法很简单,爬取速度也快. 本次爬取的豆瓣书籍排行榜的 ...
- python爬虫模块排名_Python爬虫使用lxml模块爬取豆瓣读书排行榜并分析
上次使用了beautifulsoup库爬取电影排行榜,爬取相对来说有点麻烦,爬取的速度也较慢.本次使用的lxml库,我个人是最喜欢的,爬取的语法很简单,爬取速度也快. 本次爬取的豆瓣书籍排行榜的首页地 ...
- 爬虫项目实战一:基于Scrapy+MongDB爬取并存储糗事百科用户信息
爬虫项目实战一:基于Scrapy+MongDB爬取并存储糗事百科用户信息 一.前言 二.项目目标 三.项目的环境配置 四.项目实现 1. 创建QSBK项目 2. 实现Spider 1. 实现一页网页上 ...
- 【微信小程序】获取用户信息
文章目录 获取用户信息 组件open-data button组件中的open-type 接口getUserProfile 查看授权结果 获取用户信息 组件open-data 组件 open-data用 ...
最新文章
- 高校复试计算机英语文献翻译,专业文献英语翻译复试.pdf
- 借双慧眼识别钓鱼欺诈网站
- 个人所得税的申报方式有两种,分别有什么区别?该怎么选?
- c语言min函数_C语言探索之旅 | 第一部分第十课:第一个C语言小游戏
- python numpy中bool变量转为1或0
- 【iOS】Web Color 的 Swift 实现
- 手机电脑同屏_把手游变成端游的同屏神器,就是这款Onebit“X9”了!
- Kite的学习历程SpringCloud之Seata安装
- 设计模式之责任链模式(Java实现)
- ntag213和215有什么区别_NTAG213、NTAG215和NTAG216NFC标签
- 微信小程序base64转为二维码、条形码图片
- osgearth加载倾斜摄影数据
- android star法则简历,优秀简历的STAR原则
- css 剪辑图片_css剪裁GIF背景图片动画特效
- 蓝桥杯(纯C)比赛--菜鸟级
- 《LaneAF:Robust Multi-Lane Detection with Affinity Fields》论文笔记
- 解决TensorFlow“Your CPU supports instructions TensorFlow binary was not compiled to use : AVX2 FMA”
- 2011年最新企业offer
- 怎样才能批量查询网站的谷歌PR权重?把手教你批量查询网站谷歌PR权重值
- python求向量长度_得到向量的大小(x,y)