Scrapy 爬虫实例 抓取豆瓣小组信息并保存到mongodb中

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介:

这个框架关注了很久,但是直到最近空了才仔细的看了下 这里我用的是scrapy0.24版本

先来个成品好感受这个框架带来的便捷性,等这段时间慢慢整理下思绪再把最近学到的关于此框架的知识一一更新到博客来。


最近想学git 于是把代码放到 git-osc上了: 

https://git.oschina.net/1992mrwang/doubangroupspider


先说明下这个玩具爬虫的目的

能够将种子URL页面当中的小组进行爬取 并分析出有关联的小组连接 以及小组的组员人数 和组名等信息

出来的数据大概是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{     'RelativeGroups' : [u 'http://www.douban.com/group/10127/' ,
                         u 'http://www.douban.com/group/seventy/' ,
                         u 'http://www.douban.com/group/lovemuseum/' ,
                         u 'http://www.douban.com/group/486087/' ,
                         u 'http://www.douban.com/group/lovesh/' ,
                         u 'http://www.douban.com/group/NoAstrology/' ,
                         u 'http://www.douban.com/group/shanghaijianzhi/' ,
                         u 'http://www.douban.com/group/12658/' ,
                         u 'http://www.douban.com/group/shanghaizufang/' ,
                         u 'http://www.douban.com/group/gogo/' ,
                         u 'http://www.douban.com/group/117546/' ,
                         u 'http://www.douban.com/group/159755/' ],
      'groupName' : u '\u4e0a\u6d77\u8c46\u74e3' ,
      'groupURL' 'http://www.douban.com/group/Shanghai/' ,
      'totalNumber' : u '209957' }

有啥用 其实这些数据就能够分析小组与小组之间的关联度等,如果有心还能抓取到更多的信息。不在此展开 本文章主要是为了能够快速感受一把。


首先就是 start 一个新的名为douban的项目 

# scrapy startproject douban

# cd douban

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
这是整个项目的完整后的目录 
ps  放到git-osc时候为了美观改变了项目主目录名称 clone下来无影响
mrwang@mrwang-ubuntu:~ /student/py/douban $ tree
.
├── douban
│   ├── __init__.py
│   ├── items.py            # 实体
│   ├── pipelines.py      # 数据管道文件
│   ├── settings.py        # 设置
│   └── spiders
│       ├── BasicGroupSpider.py   # 真正进行爬取的爬虫
│       └──  __init__.py
├──  nohup .out               # 我用nohup 进行后台运行生成的一个日志文件
├── scrapy.cfg
├── start.sh                    # 为了方便写的启动shell 很简单
├── stop.sh                    # 为了方便写的停止shell 很简单
└──  test .log                    # 抓取时生成的日志 在启动脚本中就有


编写实体 items.py , 主要是为了抓回来的数据可以很方便的持久化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mrwang@mrwang - ubuntu:~ / student / py / douban$ cat douban / items.py
# -*- coding: utf-8 -*-
 
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
from  scrapy.item  import  Item, Field
  
class  DoubanItem(Item):
     # define the fields for your item here like:
     # name = Field()
     groupName  =  Field()
     groupURL  =  Field()
     totalNumber  =  Field()
     RelativeGroups  =  Field()
     ActiveUesrs  =  Field()


编写爬虫并自定义一些规则进行数据的处理

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
mrwang@mrwang - ubuntu:~ / student / py / douban$ cat douban / spiders / BasicGroupSpider.py
# -*- coding: utf-8 -*-
 
from  scrapy.contrib.spiders  import  CrawlSpider, Rule
from  scrapy.contrib.linkextractors.sgml  import  SgmlLinkExtractor
from  scrapy.selector  import  HtmlXPathSelector
from  scrapy.item  import  Item
from  douban.items  import  DoubanItem
import  re
 
class  GroupSpider(CrawlSpider):
     # 爬虫名
     name  =  "Group"
     
     allowed_domains  =  [ "douban.com" ]
     # 种子链接
     start_urls  =  [
         "http://www.douban.com/group/explore?tag=%E8%B4%AD%E7%89%A9" ,
         "http://www.douban.com/group/explore?tag=%E7%94%9F%E6%B4%BB" ,
         "http://www.douban.com/group/explore?tag=%E7%A4%BE%E4%BC%9A" ,
         "http://www.douban.com/group/explore?tag=%E8%89%BA%E6%9C%AF" ,
         "http://www.douban.com/group/explore?tag=%E5%AD%A6%E6%9C%AF" ,
         "http://www.douban.com/group/explore?tag=%E6%83%85%E6%84%9F" ,
         "http://www.douban.com/group/explore?tag=%E9%97%B2%E8%81%8A" ,
         "http://www.douban.com/group/explore?tag=%E5%85%B4%E8%B6%A3"
     ]
  
      # 规则 满足后 使用callback指定的函数进行处理    
     rules  =  [
         Rule(SgmlLinkExtractor(allow = ( '/group/[^/]+/$' , )),
callback = 'parse_group_home_page' , process_request = 'add_cookie' ),
         Rule(SgmlLinkExtractor(allow = ( '/group/explore\?tag' , )), follow = True ,
process_request = 'add_cookie' ),
     ]
  
     def  __get_id_from_group_url( self , url):
         =   re.search( "^http://www.douban.com/group/([^/]+)/$" , url)
         if (m):
             return  m.group( 1
         else :
             return  0
  
     def  add_cookie( self , request):
         request.replace(cookies = [
  
         ]);
         return  request;
  
     def  parse_group_topic_list( self , response):
         self .log( "Fetch group topic list page: %s"  %  response.url)
         pass
  
  
     def  parse_group_home_page( self , response):
  
         self .log( "Fetch group home page: %s"  %  response.url)
          
         # 这里使用的是一个叫 XPath 的选择器
         hxs  =  HtmlXPathSelector(response)
         item  =  DoubanItem()
  
         #get group name
         item[ 'groupName' =  hxs.select( '//h1/text()' ).re( "^\s+(.*)\s+$" )[ 0 ]
  
         #get group id 
         item[ 'groupURL' =  response.url
         groupid  =  self .__get_id_from_group_url(response.url)
  
         #get group members number
         members_url  =  "http://www.douban.com/group/%s/members"  %  groupid
         members_text  =  hxs.select( '//a[contains(@href, "%s")]/text()'  %  members_url).re( "\((\d+)\)" )
         item[ 'totalNumber' =  members_text[ 0 ]
 
         #get relative groups
         item[ 'RelativeGroups' =  []
         groups  =  hxs.select( '//div[contains(@class, "group-list-item")]' )
         for  group  in  groups:
             url  =  group.select( 'div[contains(@class, "title")]/a/@href' ).extract()[ 0 ]
             item[ 'RelativeGroups' ].append(url)        
 
         return  item


编写数据处理的管道这个阶段我会把爬虫收集到的数据存储到mongodb当中去

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
mrwang@mrwang - ubuntu:~ / student / py / douban$ cat douban / pipelines.py
# -*- coding: utf-8 -*-
 
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import  pymongo
 
from  scrapy  import  log
from  scrapy.conf  import  settings
from  scrapy.exceptions  import  DropItem
 
class  DoubanPipeline( object ):
     def  __init__( self ):
         self .server  =  settings[ 'MONGODB_SERVER' ]
         self .port  =  settings[ 'MONGODB_PORT' ]
         self .db  =  settings[ 'MONGODB_DB' ]
         self .col  =  settings[ 'MONGODB_COLLECTION' ]
         connection  =  pymongo.Connection( self .server,  self .port)
         db  =  connection[ self .db]
         self .collection  =  db[ self .col]
 
     def  process_item( self , item, spider):
         self .collection.insert( dict (item))
         log.msg( 'Item written to MongoDB database %s/%s'  %  ( self .db,  self .col),level = log.DEBUG, spider = spider)
         return  item


在设置类中设置 所使用的数据处理管道 以及mongodb连接参数 和 user-agent 躲避爬虫被禁

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
32
33
mrwang@mrwang - ubuntu:~ / student / py / douban$ cat douban / settings.py
# -*- coding: utf-8 -*-
 
# Scrapy settings for douban project
#
# For simplicity, this file contains only the most important settings by
# default. All the other settings are documented here:
#
#     http://doc.scrapy.org/en/latest/topics/settings.html
#
 
BOT_NAME  =  'douban'
 
SPIDER_MODULES  =  [ 'douban.spiders' ]
NEWSPIDER_MODULE  =  'douban.spiders'
 
# 设置等待时间缓解服务器压力 并能够隐藏自己
DOWNLOAD_DELAY  =  2
 
RANDOMIZE_DOWNLOAD_DELAY  =  True
USER_AGENT  =  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5'
COOKIES_ENABLED  =  True
 
# 配置使用的数据管道
ITEM_PIPELINES  =  [ 'douban.pipelines.DoubanPipeline' ]
 
MONGODB_SERVER = 'localhost'
MONGODB_PORT = 27017
MONGODB_DB = 'douban'
MONGODB_COLLECTION = 'doubanGroup'
 
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'douban (+http://www.yourdomain.com)'


OK 一个玩具爬虫就简单的完成了

启动启动命令

nohup scrapy crawl Group --logfile=test.log &


===========================  2014/12/02 更新 ===================================

在github上发现已经有人 和我想的一样 重新写了一个调度器 使用mongodb进行存储需要接下来访问的页面,于是照着模仿了一遍写一个来用

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
mrwang@mrwang - ThinkPad - Edge - E431:~ / student / py / douban$ cat douban / scheduler.py
 
from  scrapy.utils.reqser  import  request_to_dict, request_from_dict
import  pymongo
import  datetime
 
class  Scheduler( object ):
     def  __init__( self , mongodb_server, mongodb_port, mongodb_db, persist, queue_key, queue_order):
         self .mongodb_server  =  mongodb_server
         self .mongodb_port  =  mongodb_port
         self .mongodb_db  =  mongodb_db
         self .queue_key  =  queue_key
     self .persist  =  persist
     self .queue_order  =  queue_order
 
     def  __len__( self ):
         return  self .client.size()
 
     @ classmethod
     def  from_crawler( cls , crawler):
     settings  =  crawler.settings
     mongodb_server  =  settings.get( 'MONGODB_QUEUE_SERVER' 'localhost' )
     mongodb_port  =  settings.get( 'MONGODB_QUEUE_PORT' 27017 )
     mongodb_db  =  settings.get( 'MONGODB_QUEUE_DB' 'scrapy' )
         persist  =  settings.get( 'MONGODB_QUEUE_PERSIST' True )
         queue_key  =  settings.get( 'MONGODB_QUEUE_NAME' None )
         queue_type  =  settings.get( 'MONGODB_QUEUE_TYPE' 'FIFO' )
 
     if  queue_type  not  in  ( 'FIFO' 'LIFO' ):
         raise  Error( 'MONGODB_QUEUE_TYPE must be FIFO (default) or LIFO' )
 
     if  queue_type  = =  'LIFO' :
         queue_order  =  - 1
     else :
         queue_order  =  1
 
         return  cls (mongodb_server, mongodb_port, mongodb_db, persist, queue_key, queue_order)
 
     def  open ( self , spider):
         self .spider  =  spider
     if  self .queue_key  is  None :
         self .queue_key  =  "%s_queue" % spider.name
 
     connection  =  pymongo.Connection( self .mongodb_server,  self .mongodb_port)
     self .db  =  connection[ self .mongodb_db]
     self .collection  =  self .db[ self .queue_key]
 
         # notice if there are requests already in the queue
     size  =  self .collection.count()
         if  size >  0 :
             spider.log( "Resuming crawl (%d requests scheduled)"  %  size)
 
     def  close( self , reason):
         if  not  self .persist:
             self .collection.drop()
 
     def  enqueue_request( self , request):
     data  =  request_to_dict(request,  self .spider)
     
     self .collection.insert({
         'data' : data,
         'created' : datetime.datetime.utcnow()
     })
 
     def  next_request( self ):
     entry  =  self .collection.find_and_modify(sort = { "$natural" : self .queue_order}, remove = True )
     if  entry:
         request  =  request_from_dict(entry[ 'data' ],  self .spider)
         return  request
     
         return  None
 
     def  has_pending_requests( self ):
         return  self .collection.count() >  0

这个默认都有配置,如果希望自定义也可以在douban/settings.py 中配置

具体的可以配置的东西有

参数名                                 默认值
MONGODB_QUEUE_SERVER=localhost  服务器
MONGODB_QUEUE_PORT=27017   端口号
MONGODB_QUEUE_DB=scrapy  数据库名
MONGODB_QUEUE_PERSIST=True  完成后是否将任务队列从mongo中删除
MONGODB_QUEUE_NAME=None 队列集合名 如果为None 默认为你爬虫的名字
MONGODB_QUEUE_TYPE=FIFO  先进先出 或者 LIFO后进先出

任务队列分离后可以方便后期将爬虫改造成为分布式突破单机限制,git-osc 已更新。

会有人考虑任务队列的效率问题,我在个人电脑上测试队列达到将近百万级对mongodb做一次比较复杂的查询,再未做任何索引的情况下出来的效果还是不错的。8G内存+I5 内存未用尽,还打开了大量程序的情况下进行,如果有人在看,也可以自行做一次测试 不算太糟糕。

wKiom1R9fQ_xqh3bAAIwhygUmqc302.jpg



本文转自  拖鞋崽  51CTO博客,原文链接:http://blog.51cto.com/1992mrwang/1583539


相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
2月前
|
数据采集 存储 JSON
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
115 6
|
2月前
|
数据采集 JSON JavaScript
如何通过PHP爬虫模拟表单提交,抓取隐藏数据
本文介绍了如何使用PHP模拟表单提交并结合代理IP技术抓取京东商品的实时名称和价格,特别是在电商大促期间的数据采集需求。通过cURL发送POST请求,设置User-Agent和Cookie,使用代理IP绕过限制,解析返回数据,展示了完整代码示例。
如何通过PHP爬虫模拟表单提交,抓取隐藏数据
|
2月前
|
数据采集 JavaScript 网络安全
为什么PHP爬虫抓取失败?解析cURL常见错误原因
豆瓣电影评分是电影市场的重要参考,通过网络爬虫技术可以高效采集评分数据,帮助电影制作和发行方优化策略。本文介绍使用PHP cURL库和代理IP技术抓取豆瓣电影评分的方法,解决反爬机制、网络设置和数据解析等问题,提供详细代码示例和优化建议。
为什么PHP爬虫抓取失败?解析cURL常见错误原因
|
2月前
|
数据采集 前端开发 JavaScript
除了网页标题,还能用爬虫抓取哪些信息?
爬虫技术可以抓取网页上的各种信息,包括文本、图片、视频、链接、结构化数据、用户信息、价格和库存、导航菜单、CSS和JavaScript、元数据、社交媒体信息、地图和位置信息、广告信息、日历和事件信息、评论和评分、API数据等。通过Python和BeautifulSoup等工具,可以轻松实现数据抓取。但在使用爬虫时,需遵守相关法律法规,尊重网站的版权和隐私政策,合理控制请求频率,确保数据的合法性和有效性。
|
2月前
|
数据采集 前端开发 中间件
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第26天】Python是一种强大的编程语言,在数据抓取和网络爬虫领域应用广泛。Scrapy作为高效灵活的爬虫框架,为开发者提供了强大的工具集。本文通过实战案例,详细解析Scrapy框架的应用与技巧,并附上示例代码。文章介绍了Scrapy的基本概念、创建项目、编写简单爬虫、高级特性和技巧等内容。
95 4
|
2月前
|
数据采集 中间件 API
在Scrapy爬虫中应用Crawlera进行反爬虫策略
在Scrapy爬虫中应用Crawlera进行反爬虫策略
|
2月前
|
数据采集 Web App开发 iOS开发
如何利用 Python 的爬虫技术获取淘宝天猫商品的价格信息?
本文介绍了使用 Python 爬虫技术获取淘宝天猫商品价格信息的两种方法。方法一使用 Selenium 模拟浏览器操作,通过定位页面元素获取价格;方法二使用 Requests 和正则表达式直接请求页面内容并提取价格。每种方法都有详细步骤和代码示例,但需注意反爬措施和法律法规。
|
5月前
|
机器学习/深度学习 数据采集 数据可视化
基于爬虫和机器学习的招聘数据分析与可视化系统,python django框架,前端bootstrap,机器学习有八种带有可视化大屏和后台
本文介绍了一个基于Python Django框架和Bootstrap前端技术,集成了机器学习算法和数据可视化的招聘数据分析与可视化系统,该系统通过爬虫技术获取职位信息,并使用多种机器学习模型进行薪资预测、职位匹配和趋势分析,提供了一个直观的可视化大屏和后台管理系统,以优化招聘策略并提升决策质量。
247 4
|
5月前
|
数据采集 存储 搜索推荐
打造个性化网页爬虫:从零开始的Python教程
【8月更文挑战第31天】在数字信息的海洋中,网页爬虫是一艘能够自动搜集网络数据的神奇船只。本文将引导你启航,用Python语言建造属于你自己的网页爬虫。我们将一起探索如何从无到有,一步步构建一个能够抓取、解析并存储网页数据的基础爬虫。文章不仅分享代码,更带你理解背后的逻辑,让你能在遇到问题时自行找到解决方案。无论你是编程新手还是有一定基础的开发者,这篇文章都会为你打开一扇通往数据世界的新窗。
|
6月前
|
数据采集 存储 JSON
从零到一构建网络爬虫帝国:HTTP协议+Python requests库深度解析
【7月更文挑战第31天】在网络数据的海洋中,使用Python的`requests`库构建网络爬虫就像探索未知的航船。HTTP协议指导爬虫与服务器交流,收集信息。HTTP请求包括请求行、头和体,响应则含状态行、头和体。`requests`简化了发送各种HTTP请求的过程。
100 4