以前总认为坚持会让我们变强大,但是长大后才发现,让我们强大的,是放下!
总结:
- span里面 直接是文本用 /text(); 或者// text();
response.xpath("//div[@class="comment-item"]//span[@class="short"]/text()")
response.xpath("//div[@class="comment-item"]//span[@class="short"]//text()")
1. Scrapy-redis组件
这是一个能给Scrapy框架引入分布式的组件。
分布式由Redis提供,可以在不同节点上运行爬虫,共用同一个Redis实例。在Redis中存储待爬取的URLs、Items。
1.1 安装
$ pip install scrapy-redis
安装要求
Python 2.7, 3.4 or 3.5 Redis >= 2.8
Scrapy >= 1.0 redis-py >= 2.10
#---------------------------------------------
Installing collected packages: scrapy-redis, zope.interface
Successfully installed scrapy-redis-0.6.8 zope.interface-5.1.0
1.2 配置
# Enables scheduling storing requests queue in redis.
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# Ensure all spiders share same duplicates filter through redis.
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# Store scraped item in redis for post-processing.
ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 300}
# The item pipeline serializes and stores the items in this redis key.
# 这个key很重要
#REDIS_ITEMS_KEY = '%(spider)s:items'
# Specify the host and port to use when connecting to Redis (optional).
#REDIS_HOST = 'localhost'
#REDIS_PORT = 6379
# Default start urls key for RedisSpider and RedisCrawlSpider.
#REDIS_START_URLS_KEY = '%(name)s:start_urls'
在以下方面做了增强
Scheduler + Duplication Filter, Item Pipeline, Base Spiders
Scheduler
本质上将原来的普通队列,变成了redis以提供多爬虫多进程共享,并行能力增强。Duplication Filter
scrapy使用set来去重,scrapy-redis使用redis的set类型去重 Item PipelineItem Pipelline
在Item Pipeline增加一个处理,即将数据items存入redis的items queue中 Base SpidersBase Spiders
提供了使用了RedisMixin的RedisSpider和RedisCrawlSpider,从Redis中读取Url。
Redis是服务,爬虫就是它的客户端,客户端就可以扩展出并行的很多爬虫一起爬取。
2. redis安装
这里不再赘述。
3. 豆瓣影评分析项目
(F:\Pyenv\conda3.8) F:\Projects\spider>scrapy startproject dbreview .
(F:\Pyenv\conda3.8) F:\Projects\spider>scrapy genspider -t crawl review douban.com
Created spider 'review' using template 'crawl' in module:
dbreview.spiders.review
3.1 抓取内容分析
抓取最新top 1电影,分析其影评
提取影评的xpath = //div[@class="comment-item"]//span[@class="short"]
3.2 创建Scrapy项目
$ scrapy startproject review .
3.3 配置
# settings
BOT_NAME = 'dbreview'
SPIDER_MODULES = ['dbreview.spiders']
NEWSPIDER_MODULE = 'dbreview.spiders'
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36"
ROBOTSTXT_OBEY = False
CONCURRENT_REQUESTS = 4
DOWNLOAD_DELAY = 1
COOKIES_ENABLED = False # 每一次全新的请求;
# Disable Telnet Console (enabled by default)
#TELNETCONSOLE_ENABLED = False
# Enable or disable spider middlewares
# See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
# 'dbreview.middlewares.DbreviewSpiderMiddleware': 543,
#}
# Enable or disable downloader middlewares
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
#DOWNLOADER_MIDDLEWARES = {
# 'dbreview.middlewares.DbreviewDownloaderMiddleware': 543,
#}
# Enable or disable extensions
# See https://docs.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# ITEM_PIPELINES = {
# # 'dbreview.pipelines.DbreviewPipeline': 299,
# 'scrapy_redis.pipelines.RedisPipeline': 300
# }
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
REDIS_HOST = '192.168.0.100'
REDIS_PORT = 6379
3.4 构建Item
import scrapy
class ReviewItem(scrapy.Item):
review = scrapy.Field()
# spider
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import DbreviewItem
class ReviewSpider(CrawlSpider):
name = 'review'
allowed_domains = ['douban.com']
start_urls = ['https://movie.douban.com/subject/26357307/comments']
rules = (
Rule(LinkExtractor(allow=r'start=\d+'), callback='parse_item', follow=True),
)
def parse_item(self, response):
item = DbreviewItem()
item['comment'] = response.xpath('//div[@class="comment-item"]//span[@class="short"]/text()').extract_first()
print(dict(item), '+++++++++++++')
yield item
3.5 构建爬虫scrapy-redis
写完先测试,然后将类型改为RedisCrawlSpider
$ scrapy genspider -t crawl dbreview douban.com
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import DbreviewItem
from scrapy_redis.spiders import RedisCrawlSpider
class ReviewSpider(RedisCrawlSpider):
name = 'review'
allowed_domains = ['douban.com']
start_urls = ['https://movie.douban.com/subject/26357307/comments']
rules = (
Rule(LinkExtractor(allow=r'start=\d+'), callback='parse_item', follow=True),
)
def parse_item(self, response):
item = DbreviewItem()
item['comment'] = response.xpath('//div[@class="comment-item"]//span[@class="short"]/text()').extract_first()
print(dict(item), '+++++++++++++')
yield item
爬取
$ scrapy crawl dbreview
会发现程序会卡住,这是因为在等待起始URL,手动添加开始url127.0.0.1:6379> lpush myspider:start_urls https://movie.douban.com/subject/26357307/comments
3.6 分析
使用爬虫,爬取所有数据,然后使用redis中的数据开始分析
import redis
import simplejson
db = redis.Redis('192.168.0.100')
print(db.keys('*'))
reviewlist = db.lrange('review:items', 0, -1)
for comment in reviewlist:
try:
review = simplejson.loads(comment).get('comment')
print(review)
print('-----------------------')
except Exception as e:
print(e)
#--------------------------------------------------------
迪士尼撸出来的玩意,糟蹋了一个好题材,一帮中国演员说着不那么标准的英语在那里拿腔拿调的念台词真是尴尬至极
-----------------------
(70/100)工整流畅合格的商业片。迪士尼公主电影里品质上乘的存在。刘亦菲的表演是没有问题的,动作戏精彩,画面质感一流,片尾出字幕时的title design超好看。中国公主花木兰没有让人失望。
-----------------------
太出戏了,河北土楼?Niubi
-----------------------
跟玩似的,弱智一群人,成就一个人。
真实与逻辑并不需要。
-----------------------
先说结论:壳是中国壳,魂还是老外那个劲,造型是日本艺伎,内核是老美超级英雄主义。
总之是外国对中国片面化的认识。
。。。。。。
看完挺不适的,电影还是明显的迪士尼风格。能理解迪士尼想凸现花木兰的英勇女性角色,但是如果这种精神是以贬低中国和女性为衬托,那么我表示拒绝!整体挺局限的,从巩俐女巫角色的莫名其妙到刚训练不久的几人小队拯救国家和皇帝,再到整体营造的女性以三从四德和嫁人为荣耀的奇怪思想。多种文化杂糅,多重风格杂糅。影片显然不了解中国文化和花木兰精神。大概从头至尾最能提现花木兰精神的就是剑上那几个字了吧。
-----------------------
1. jieba分词——结巴分词
安装 pip install jieba
官网 https://github.com/fxsjy/jieba
测试代码
import jieba
seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
seg_list = jieba.lcut("他来到了网易杭研大厦") # 默认是精确模式
print(seg_list)
seg_list = jieba.lcut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") # 搜索引擎模式
print(seg_list)
# ------------------------------------------------
Full Mode: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学
Default Mode: 我/ 来到/ 北京/ 清华大学
['他', '来到', '了', '网易', '杭研', '大厦']
['小明', '硕士', '毕业', '于', '中国', '科学', '学院', '科学院', '中国科学院', '计算', '计算所', ',', '后', '在', '日本', '京都', '大学', '日本京都大学', '深造']
2. stopword 停用词
数据清洗:把脏数据洗掉。检测出并去除掉数据中无效或无关的数据。例如,空值、非法值的检测,重复数据检测等。
对于一条条影评来说,我们分析的数据中包含了很多无效的数据,比如标点符号、英文的冠词、中文"的"等等,需要把它们清除掉。
使用停用词来去除这些无效的数据。
wordcloud词云 https://amueller.github.io/word_cloud/index.html
依赖numpy、matplotlib
pip install wordcloud
matplotlib:python中绘制二维图的模块。
pip install matplotlib
常用方法
WordCloud参数
font_path:指明要用的字体的路径
width:默认值400。设定词云画布的宽度
height:默认值200。画布高度
mask:默认无。用来设定词云的形状
min_font_size:默认值4,整数类型。设定最小的词的尺寸/大小
max_font_size:默认无,整数型。设定最大词的大小
max_words:默认值200。设定词云最多显示的词的个数
background_color:默认值为黑色。设定词云画布底色
Scale:默认值1。值越大,图像密度越大越清晰
import redis
import simplejson, jieba
form wordcloud import WordCloud
import matplotlib.pyplot as plt
# 使用停用词
stopwords = set()
with open('./chineseStopWords.txt', encoding='gbk') as f:
for line in f:
stopwords.add(line.rstrip('\r\r'))
stopwords.add(' ')
# 分析
db = redis.Redis('192.168.0.100')
print(db.keys('*'))
reviewlist = db.lrange('review:items', 0, -1)
words = {}
total = 0
for comment in reviewlist:
try:
review = simplejson.loads(comment).get('comment')
print(review)
for word in jieba.cut(review):
if word in stopwords:
words[word] = words.get(word, 0) + 1
total += 1
print('-----------------------')
except Exception as e:
print(e)
print(words)
print(sorted(words.items(), key=lambda x: x[1], reverse=True))
# 词云
frenq = {word:count/total for word, count in words.items()}
# 用什么字体、背景色、最大字体
wordcloud = WordCloud(font_path='simhei.ttf', max_font_size=40, scale=15)
wordcloud.fit_words(frenq) # 使用单词和词频创建词
plt.figure(2)
plt.imshow(wordcloud, interpolation="bilinear") # 将一个图显示在二维坐标
plt.axis("off") # 不打印坐标系
plt.show()