新接触爬虫,经过一段时间的实践,写了几个简单爬虫,爬取豆瓣电影的爬虫例子网上有很多,但都很简单,大部分只介绍了请求页面和解析部分,对于新手而言,我希望能够有一个比较全面的实例。所以找了很多实例和文章,并整合在一起,在现有豆瓣爬虫的基础上,增加了一些内容,算是比较全的内容了。主要包括项目建立、请求页面、xpath解析、自动翻页、数据输出、编码处理等等。。
System Version:Ubuntu 16.04
Python Version:3.5.2
Scrapy Version:1.5.0
执行如下命令建立scrapy爬虫项目
scrapy startproject spider_douban
命令执行完成后,建立了spider_douban
文件夹,目录结构如下:
.
2.建立爬虫数据模型
├── scrapy.cfg
└── spider_douban
├── __init__.py
├── items.py
├── middlewares.py
├── pipelines.py
├── settings.py
└── spiders
├── douban_spider.py
└── __init__.py
打开./spider_douban/items.py
文件,编辑内容如下:
import scrapy
3.新建爬虫文件
class DoubanMovieItem(scrapy.Item):
# 排名
ranking = scrapy.Field()
# 电影名称
movie_name = scrapy.Field()
# 评分
score = scrapy.Field()
# 评论人数
score_num = scrapy.Field()
新建./spiders/douban_spider.py
文件,编辑内容如下:
from scrapy import Request
from scrapy.spiders import Spider
from spider_douban.items import DoubanMovieItem
class DoubanMovieTop250Spider(Spider):
name = 'douban_movie_top250'
start_urls = {
'https://movie.douban.com/top250'
}
'''
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
}
def start_requests(self):
url = 'https://movie.douban.com/top250'
yield Request(url, headers=self.headers)
'''
def parse(self, response):
item = DoubanMovieItem()
movies = response.xpath('//ol[@class="grid_view"]/li')
print(movies)
print('=============================================')
for movie in movies:
item['ranking'] = movie.xpath(
'.//div[@class="pic"]/em/text()').extract()[0]
item['movie_name'] = movie.xpath(
'.//div[@class="hd"]/a/span[1]/text()').extract()[0]
item['score'] = movie.xpath(
'.//div[@class="star"]/span[@class="rating_num"]/text()'
).extract()[0]
item['score_num'] = movie.xpath(
'.//div[@class="star"]/span/text()').re(r'(\d+)人评价')[0]
yield item
next_url = response.xpath('//span[@class="next"]/a/@href').extract()
if next_url:
next_url = 'https://movie.douban.com/top250' + next_url[0]
yield Request(next_url)
douban_spider.py
文件主要有几部分构成。
from scrapy import Request
from scrapy.spiders import Spider
from spider_douban.items import DoubanMovieItem
Request
类用于请求要爬取的页面数据Spider
类是爬虫的基类DoubanMovieItem
是我们第一步建立的爬取数据模型
基于spider
类定义的爬虫类DoubanMovieTop250Spider
中,首先定义爬虫的基本信息:
name:在项目中爬虫的名称,可以在项目目录中执行
scrapy list
获取已经定义的爬虫列表start_urls:是爬取的第一个页面地址
headers:是向web服务器发送页面请求的时候附加的user-agent消息,告诉web服务器是什么类型的浏览器或设备在请求页面,对于不具备简单反爬机制的网站,headers部分可以省略。
为了迷惑web服务器,一般会在爬虫发送web请求的时候定义user-agent信息,这里有两种写法。
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
}
def start_requests(self):
url = 'https://movie.douban.com/top250'
yield Request(url, headers=self.headers)
可以看到,这种写法中,start_urls
定义没有了,转而定义了start_requests
函数,开始的url写到了函数里。同时,定义了headers字典,在发送Request请求的时候,将headers字典一并发送。这种写法简单直观,缺点是在一个爬虫项目执行期间,所有请求都是一个User-Agent属性。
start_urls = {
'https://movie.douban.com/top250'
}
简单、直接的定义start_urls属性,而Request中的header属性通过其他方法另外定义,容后再说。
逐句分解说明
1.基于我们定义的DoubanMovieItem类创建item实例
item = DoubanMovieItem()
2.解析页面 – 获取内容框架
通过分析页面源码,我们能够看到,页面中的电影信息是保存在了
标签中,这个
标签有一个独特的样式表grid_view
,而每一个单独的电影信息保存在了标签中,下面代码获取
class
属性为grid_view
的
标签下的所有标签内容。
movies = response.xpath(‘//ol[@class=”grid_view”]/li’)
3.解析页面 – 获取分项
在每一个标签中,还有内部结构,通过xpath()解析,将每一项内容解析出来,赋值给item实例中的各个字段。通过查看
movie.douban.com/top250
页面的源码可以很容易找到这个标签定义的内容。如果我们通过type()函数查看movies的变量类型,可以发现他的类型是
。
标签中的每一个标签都是这个列表中的一项,那么就可以对movies做迭代。
首先看看标签中的页面结构:
可以看到要提取数据的各部分所在标签位置:
排名:class属性为pic的
标签下,,
标签中…
电影名:class属性为hd的
标签下,
标签中的第一个
标签…
评分:class属性为star的
标签下,class属性为rating_num的
标签中…
评论人数:class属性为star的
标签下,
标签中。由于使用了re正则表达式,所以没有特别指定是哪一个
标签。
回到代码部分,对之前定义的movies做迭代,逐项获取要抓取的数据。
for movie in movies:
item['ranking'] = movie.xpath(
'.//div[@class="pic"]/em/text()').extract()[0]
item['movie_name'] = movie.xpath(
'.//div[@class="hd"]/a/span[1]/text()').extract()[0]
item['score'] = movie.xpath(
'.//div[@class="star"]/span[@class="rating_num"]/text()'
).extract()[0]
item['score_num'] = movie.xpath(
'.//div[@class="star"]/span/text()').re(r'(\d+)人评价')[0]
yield item4.Url跳转(翻页)
如果到此为止,我们可以将
https://movie.douban.com/top250
页面中的第一页内容爬取到,但只有25项记录,要爬取全部的250条记录,就要执行下面代码:
next_url = response.xpath('//span[@class="next"]/a/@href').extract()
if next_url:
next_url = 'https://movie.douban.com/top250' + next_url[0]
yield Request(next_url)首先通过xpath解析了页面中
4.处理随机Head属性(随机User-Agent)后页
的链接,并赋值给next_url变量,如果我们当前在第一页,那么解析后页
的链接就是?start=25&filter=
。将解析的后页链接与完整url连接形成完整的地址,再次执行Request(),就实现了对全部250条记录的爬取。注意:通过xpath解析出的结果是列表,所以在引用的时候写成next_url[0]
。实现随机的head属性发送。主要改两个文件:
settings.py
USER_AGENT_LIST = [
'zspider/0.9-dev http://feedback.redkolibri.com/',
'Xaldon_WebSpider/2.0.b1',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) Speedy Spider (http://www.entireweb.com/about/search_tech/speedy_spider/)',
'Mozilla/5.0 (compatible; Speedy Spider; http://www.entireweb.com/about/search_tech/speedy_spider/)',
'Speedy Spider (Entireweb; Beta/1.3; http://www.entireweb.com/about/search_tech/speedyspider/)',
'Speedy Spider (Entireweb; Beta/1.2; http://www.entireweb.com/about/search_tech/speedyspider/)',
'Speedy Spider (Entireweb; Beta/1.1; http://www.entireweb.com/about/search_tech/speedyspider/)',
'Speedy Spider (Entireweb; Beta/1.0; http://www.entireweb.com/about/search_tech/speedyspider/)',
'Speedy Spider (Beta/1.0; www.entireweb.com)',
'Speedy Spider (http://www.entireweb.com/about/search_tech/speedy_spider/)',
'Speedy Spider (http://www.entireweb.com/about/search_tech/speedyspider/)',
'Speedy Spider (http://www.entireweb.com)',
'Sosospider+(+http://help.soso.com/webspider.htm)',
'sogou spider',
'Nusearch Spider (www.nusearch.com)',
'nuSearch Spider (compatible; MSIE 4.01; Windows NT)',
'lmspider (lmspider@scansoft.com)',
'lmspider lmspider@scansoft.com',
'ldspider (http://code.google.com/p/ldspider/wiki/Robots)',
'iaskspider/2.0(+http://iask.com/help/help_index.html)',
'iaskspider',
'hl_ftien_spider_v1.1',
'hl_ftien_spider',
'FyberSpider (+http://www.fybersearch.com/fyberspider.php)',
'FyberSpider',
'everyfeed-spider/2.0 (http://www.everyfeed.com)',
'envolk[ITS]spider/1.6 (+http://www.envolk.com/envolkspider.html)',
'envolk[ITS]spider/1.6 ( http://www.envolk.com/envolkspider.html)',
'Baiduspider+(+http://www.baidu.com/search/spider_jp.html)',
'Baiduspider+(+http://www.baidu.com/search/spider.htm)',
'BaiDuSpider',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0) AddSugarSpiderBot www.idealobserver.com',
]
DOWNLOADER_MIDDLEWARES = {
'spider_douban.middlewares.RandomUserAgentMiddleware': 400,
'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,
}
USER_AGENT_LIST
定义了一些浏览器user-agent属性,网上有很多,可以找来直接加进去,需要注意的是有些user-agent信息是移动设备(手机或平板)的,如果不注意的话,可能请求到的数据与你看到的数据有较大差异;DOWNLOADER_MIDDLEWARES
定义了下载器中间件,它在发送页面请求数据的时候被调用。middlewares.py
from spider_douban.settings import USER_AGENT_LIST
import random
class RandomUserAgentMiddleware():
def process_request(self, request, spider):
ua = random.choice(USER_AGENT_LIST)
if ua:
request.headers.setdefault('User-Agent', ua)在
5.结果保存RandomUserAgentMiddleware()
中,每次发送请求数据,会在USER_AGENT_LIST
中随机选择一条User-Agent
记录。编辑
pipelines.py
文件:
from scrapy import signals
from scrapy.contrib.exporter import CsvItemExporter
class SpiderDoubanPipeline(CsvItemExporter):
def __init__(self):
self.files = {}
@classmethod
def from_crawler(cls, crawler):
print('==========pipeline==========from_crawler==========')
pipeline = cls()
crawler.signals.connect(pipeline.spider_opened, signals.spider_opened)
crawler.signals.connect(pipeline.spider_closed, signals.spider_closed)
return pipeline
def spider_opened(self, spider):
savefile = open('douban_top250_export.csv', 'wb+')
self.files[spider] = savefile
print('==========pipeline==========spider_opened==========')
self.exporter = CsvItemExporter(savefile)
self.exporter.start_exporting()
def spider_closed(self, spider):
print('==========pipeline==========spider_closed==========')
self.exporter.finish_exporting()
savefile = self.files.pop(spider)
savefile.close()
def process_item(self, item, spider):
print('==========pipeline==========process_item==========')
print(type(item))
self.exporter.export_item(item)
return item
SpiderDoubanPipeline
类是建立项目的时候自行建立的,为了保存文件,做了修改。def from_crawler(cls, crawler):
- 如果存在,则调用此类方法从Crawler创建pipeline实例。它必须返回一个新的pipeline实例。抓取对象提供对所有Scrapy核心组件的访问,如settings和signals; 这是pipeline访问它们并将其功能挂接到Scrapy的一种方式。
在此方法中,定义了一个数据收集器(cls)的实例:‘pipeline’。
signals:Scrapy使用信号来通知事情发生。您可以在您的Scrapy项目中捕捉一些信号(使用 extension)来完成额外的工作或添加额外的功能,扩展Scrapy。虽然信号提供了一些参数,不过处理函数不用接收所有的参数 – 信号分发机制(singal dispatching mechanism)仅仅提供处理器(handler)接受的参数。您可以通过 信号(Signals) API 来连接(或发送您自己的)信号。
connect:链接一个接收器函数(receiver function) 到一个信号(signal)。signal可以是任何对象,虽然Scrapy提供了一些预先定义好的信号。
def spider_opened(self, spider):
- 当spider开始爬取时发送该信号。该信号一般用来分配spider的资源,不过其也能做任何事。该信号支持返回deferreds。
此方法中,创建了一个文件对象实例:
savefile
。CsvItemExporter(savefile):输出 csv 文件格式. 如果添加 fields_to_export 属性, 它会按顺序定义CSV的列名.
def spider_closed(self, spider):
- 当某个spider被关闭时,该信号被发送。该信号可以用来释放每个spider在 spider_opened 时占用的资源。该信号支持返回deferreds。
def process_item(self, item, spider):
- 每个item pipeline组件都需要调用该方法,这个方法必须返回一个 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理。
启用pipeline
为了让我们定义的pipeline生效,要在settings.py文件中,打开
ITEM_PIPELINES
注释:
ITEM_PIPELINES = {
6.执行爬虫
'spider_douban.pipelines.SpiderDoubanPipeline': 300,
}
scrapy crawl douban_movie_top250
执行爬虫能够看到爬取到的数据。。。
如果之前pipeline部分代码没有写,也可以用下面的命令,在爬虫执行的时候直接导出数据:
scrapy crawl douban_movie_top250 -o douban.csv
增加
7.文件编码的问题-o
参数,可以将爬取到的数据保存到douban.csv
文件中。。我在linux服务器执行爬虫,生成csv文件后,在win7系统中用excel打开变成乱码。在网上找了一些文章,有的文章直接改变linux文件默认编码,但是感觉这么做会对其他项目产生影响。最后选择一个相对简单的方式。按这几步执行就可以:
- 不要直接用excel打开csv文件。先打开excel,建立空白工作表。
- 选择
数据
选项卡,打开获取外部数据
中的自文本
。- 在
导入文本文件
对话框中选择要导入的csv文件。- 在
文本导入向导 - 第1步
中,设置文件原始格式
为65001 : Unicode (UTF-8)
- 继续下一步选择逗号分隔,就可以导入正常文本了。
写下你的评论吧 !推荐阅读
本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]蜡笔小新 2023-12-14 18:28:01 本文介绍了如何去除Win7快捷方式的箭头的方法,通过生成一个透明的ico图标并将其命名为Empty.ico,将图标复制到windows目录下,并导入注册表,即可去除箭头。这样做可以改善默认快捷方式的外观,提升桌面整洁度。 ... [详细]蜡笔小新 2023-12-14 16:17:05 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]蜡笔小新 2023-12-14 14:25:33 本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]蜡笔小新 2023-12-14 10:53:48 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]蜡笔小新 2023-12-14 08:57:59 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]蜡笔小新 2023-12-13 16:50:29 本文介绍了Webmin远程命令执行漏洞CVE-2019-15107的漏洞详情和复现方法,同时提供了防护方法。漏洞存在于Webmin的找回密码页面中,攻击者无需权限即可注入命令并执行任意系统命令。文章还提供了相关参考链接和搭建靶场的步骤。此外,还指出了参考链接中的数据包不准确的问题,并解释了漏洞触发的条件。最后,给出了防护方法以避免受到该漏洞的攻击。 ... [详细]蜡笔小新 2023-12-13 16:14:53 本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]蜡笔小新 2023-12-13 04:59:58 本文介绍了在CentOS 6.5上安装VMware Tools及解决共享文件夹显示问题的方法。包括清空CD/DVD使用的ISO镜像文件、创建挂载目录、改变光驱设备的读写权限等步骤。最后给出了拷贝解压VMware Tools的操作。 ... [详细]蜡笔小新 2023-12-12 18:18:49 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]蜡笔小新 2023-12-14 18:48:02 本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]蜡笔小新 2023-12-14 18:24:10 ubuntu用sqoop将数据从hive导入mysql时,命令: ... [详细]蜡笔小新 2023-12-12 18:56:13 本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]蜡笔小新 2023-12-12 17:12:51 linjiabin43这个家伙很懒,什么也没留下!Tags | 热门标签RankList | 热门文章
- 1python安装pandas错误怎么解决,在Python中我安装了pandas,但它无法正常工作
- 2css代码的规范整理
- 3人工智能学习笔记理解深度学习中的前向传播和反向传播算法
- 4首字母:大写;也会影响占位符 - text-transform: capitalize; Also affects Placeholder
- 5辛星浅析raid
- 6Java通过递归算法解决迷宫与汉诺塔及八皇后问题
- 7opencv练习6图像的基础操作
- 8开发笔记:udp协议与进程结合(群聊)
- 9消费级物联卡与工业级物联卡区别之处在哪里
- 10接口自动化小白之如何处理json请求参数
- 11末尾|这一点_Python print() 函数,在同一行打印
- 12LAMP架构调优(一)——隐藏Apache版本信息
- 13Django调用支付宝支付接口
- 14C++内嵌汇编
- 15使用正则表达式快速清洗NLP训练数据的技术详解实战
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有