基于python框架Scrapy爬取自己的博客内容过程详解


Posted in Python onAugust 05, 2019

前言

python中常用的写爬虫的库常有urllib2、requests,对于大多数比较简单的场景或者以学习为目的,可以用这两个库实现。这里有一篇我之前写过的用urllib2+BeautifulSoup做的一个抓取百度音乐热门歌曲的例子,有兴趣可以看一下。

本文介绍用Scrapy抓取我在博客园的博客列表,只抓取博客名称、发布日期、阅读量和评论量这四个简单的字段,以求用较简单的示例说明Scrapy的最基本的用法。

环境配置说明

操作系统:Ubuntu 14.04.2 LTS

Python:Python 2.7.6

Scrapy:Scrapy 1.0.3

注意:Scrapy1.0的版本和之前的版本有些区别,有些类的命名空间改变了。

创建项目

执行如下命令创建一个Scrapy项目

scrapy startproject scrapy_cnblogs

创建之后查看项目的目录结构如下:

scrapy_cnblogs
 ├── botcnblogs
 │ ├── __init__.py
 │ 
├── items.py  #用于定义抓取内容的实体
 │ 
├── pipelines.py #处理抓取的item的管道
 │ 
├── settings.py #爬虫需要的配置参数在这里
 │ └── spiders
 │ 
 └── __init__.py
 └── scrapy.cfg   #项目的配置文件,可以不去理会,默认即可

其中scrapy.cfg所在的目录为项目的根目录,此文件是项目的配置文件,项目建立后,此文件的内容可以不用理会。其内容如下:

[settings]
default = botcnblogs.settings
[deploy]
#url = http://localhost:6800/
project = botcnblogs

在items.py文件里定义在抓取网页内容中抽象出来的数据结构的定义,由于这里需要博客名称、发布日期、阅读量和评论量这四个字段,定义的Item结构如下:

from scrapy import Item,Field #引入Item、Field
class BotcnblogsItem(Item):
 # define the fields for your item here like:
 title = Field()  #标题
 publishDate = Field() #发布日期
 readCount = Field() #阅读量
 commentCount = Field() #评论数<br data-filtered="filtered"><br data-filtered="filtered">

在pipelines.py里对爬虫抓取到的信息(这里的信息是已经组织好的上面定义的Item对象)进行处理,官方介绍的典型的应用场景为:

  • 清理HTML数据
  • 验证爬取的数据(检查item包含某些字段)
  • 查重(并丢弃)
  • 将爬取结果保存到数据库中

它的定义也很简单,只需要实现process_item方法即可,此方法有两个参数,一个是item,即要处理的Item对象,另一个参数是spider,即爬虫。

另外还有open_spider和close_spider两个方法,分别是在爬虫启动和结束时的回调方法。

本例中处理很简单,只是将接收的Item对象写到一个json文件中,在__init__方法中以“w+”的方式打开或创建一个item.json的文件,然后把对象反序列化为字符串,写入到item.json文件中。代码如下:

# -*- coding: utf-8 -*- 
import json 
class BotcnblogsPipeline(object):
 def __init__(self):
  self.file = open("item.json", "w+") 
 def process_item(self, item, spider):
  record = json.dumps(dict(item), ensure_ascii=False)+"\n" #此处如果有中文的话,要加上ensure_ascii=False参数,否则可能出现乱码
  self.file.write(record)
  return item 
 def open_spider(self, spider):
  pass 
 def close_spider(self, spider):
  self.file.close()

setting.py是爬虫的配置文件,配置爬虫的一些配置信息,这里用到的就是设置pipelines的ITEM_PIPELINES参数,此参数配置项目中启用的pipeline及其执行顺序,以字典的形式存在,{“pipeline”:执行顺序整数}

此例中的配置如下:

SPIDER_MODULES = ['botcnblogs.spiders']
NEWSPIDER_MODULE = 'botcnblogs.spiders'
ITEM_PIPELINES = {
 'botcnblogs.pipelines.BotcnblogsPipeline': 1,
}

准备工作都做好了,爬虫呢,爬虫在哪里实现呢,我们看到项目中有个spiders目录,里面只有一个init.py文件,没错,爬虫文件需要自己创建,就在这个目录下,这里创建一个botspider.py的文件,对网页进行解析的工作就要在这里实现了,此例中定义的爬虫类继承自CrawlSpider类。

定义一个Spider需要如下几个变量和方法实现:

name:定义spider名字,这个名字应该是唯一的,在执行这个爬虫程序的时候,需要用到这个名字。

allowed_domains:允许爬取的域名列表,例如现在要爬取博客园,这里要写成cnblogs.com

start_urls:爬虫最开始爬的入口地址列表。

rules:如果要爬取的页面不是单独一个或者几个页面,而是具有一定的规则可循的,例如爬取的博客有连续多页,就可以在这里设置,如果定义了rules,则需要自己定义爬虫规则(以正则表达式的方式),而且需要自定义回调函数。

代码说话:

#-*- coding:utf-8 -*-
__author__ = 'linuxfengzheng'
from scrapy.spiders import Spider, Rule
from scrapy.selector import Selector
from botcnblogs.items import BotcnblogsItem
from scrapy.linkextractors import LinkExtractor
import re
from scrapy.spiders import CrawlSpider 
class botspider(CrawlSpider):
 name = "cnblogsSpider" #设置爬虫名称 
 allowed_domains = ["cnblogs.com"] #设置允许的域名
 start_urls = [
  "http://www.cnblogs.com/fengzheng/default.html?page=3", #设置开始爬取页面
 ] 
 rules = (
  Rule(LinkExtractor(allow=('fengzheng/default.html\?page\=([\d]+)', ),),callback='parse_item',follow=True),
 ) #制定规则
  def parse_item(self, response):
  sel = response.selector
  posts = sel.xpath('//div[@id="mainContent"]/div/div[@class="day"]')
  items = []
  for p in posts:
   #content = p.extract()
   #self.file.write(content.encode("utf-8"))
   item = BotcnblogsItem()
   publishDate = p.xpath('div[@class="dayTitle"]/a/text()').extract_first()
 
   item["publishDate"] = (publishDate is not None and [publishDate.encode("utf-8")] or [""])[0]
   #self.file.write(title.encode("utf-8"))
   title = p.xpath('div[@class="postTitle"]/a/text()').extract_first()
   item["title"] = (title is not None and [title.encode("utf-8")] or [""])[0]
 
   #re_first("posted @ 2015-11-03 10:32 风的姿态 阅读(\d+")
 
   readcount = p.xpath('div[@class="postDesc"]/text()').re_first(u"阅读\(\d+\)")
 
   regReadCount = re.search(r"\d+", readcount)
   if regReadCount is not None:
    readcount = regReadCount.group()
   item["readCount"] = (readcount is not None and [readcount.encode("utf-8")] or [0])[0]
 
   commentcount = p.xpath('div[@class="postDesc"]/text()').re_first(u"评论\(\d+\)")
   regCommentCount = re.search(r"\d+", commentcount)
   if regCommentCount is not None:
    commentcount = regCommentCount.group()
   item["commentCount"] = (commentcount is not None and [commentcount.encode("utf-8")] or [0])[0]
   items.append(item) 
  return items
  #self.file.close()

因为1.0版和之前的版本在包上有所改变,这里列出此例中所涉及的不同版本的区别

所在包
1.0版本 之前版本
spider scrapy.spiders scrapy.spider
crawlspider scrapy.spiders scrapy.contrib.spiders
linkextractor scrapy.linkextractors scrapy.contrib.linkextractors
rule scrapy.spiders scrapy.contrib.spiders

爬虫思路:

首先进入到我的博客页面http://www.cnblogs.com/fengzheng/,这是我的博客首页,以列表形式显示已经发布的博文,这是第一页,点击页面下面的下一页按钮,进入第二页,页面地址为http://www.cnblogs.com/fengzheng/default.html?page=2,由此看出网站以page作为参数来表示页数,这样看来爬虫的规则就很简单了, fengzheng/default.html\?page\=([\d]+),这个就是爬虫的规则,爬取default.html页面,page参数为数字的页面,这样无论有多少页都可以遍历到。

当然,如果页面数量很少可以在start_urls列表中,将要爬取的页面都列出来,但是这样当博文数量增多就会出现问题,如下:

start_urls = [
  "http://www.cnblogs.com/fengzheng/default.html?page=1",
  "http://www.cnblogs.com/fengzheng/default.html?page=2",
  "http://www.cnblogs.com/fengzheng/default.html?page=3",
 ]

当爬取的网页具有规则定义的情况下,要继承CrawlSpider爬虫类,使用Spider就不行了,在规则定义(rules)时,如果要对爬取的网页进行处理,而不是简单的需要Url,这时,需要定义一个回调函数,在爬取到符合条件的网页时调用,并且设置follow=Ture,定义如下:

rules = (
  Rule(LinkExtractor(allow=('fengzheng/default.html\?page\=([\d]+)', ),),callback='parse_item',follow=True),
 )

回调函数名称为parse_item,在parse_item方法中,就是真正要分析网页html,获取需要的内容的时候了。观察页面,查看需要的信息在什么位置,如图:

基于python框架Scrapy爬取自己的博客内容过程详解

之后,分析网页源码,分析出xpath

基于python框架Scrapy爬取自己的博客内容过程详解

用如下代码找到所有的class为day的div,每一个就是一个博文区域:

posts = sel.xpath('//div[@id="mainContent"]/div/div[@class="day"]')

之后遍历这个集合,获取所需内容,其中注意一下几点:

因为有中文内容,要对获取的内容进行encode("utf-8")编码

由于评论数和阅读量混在一起,要对那个字符串再进行正则表达式提取 

至此,简单的爬虫已经完成,接下来要运行这个爬虫,cd进入到爬虫项目所在的目录,执行以下命令:

scrapy crawl cnblogsSpider

会输出爬取过程信息

基于python框架Scrapy爬取自己的博客内容过程详解

之后会看到,根目录中多了一个item.json文件,cat此文件内容,可以看到信息已经被提取出来:

基于python框架Scrapy爬取自己的博客内容过程详解

点击这里在github获取源码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python抓取京东商城手机列表url实例代码
Dec 18 Python
Python实现求数列和的方法示例
Jan 12 Python
numpy找出array中的最大值,最小值实例
Apr 03 Python
python用post访问restful服务接口的方法
Dec 07 Python
根据tensor的名字获取变量的值方式
Jan 04 Python
GDAL 矢量属性数据修改方式(python)
Mar 10 Python
python如何判断IP地址合法性
Apr 05 Python
Python退出时强制运行一段代码的实现方法
Apr 29 Python
filter使用python3代码进行迭代元素的实例详解
Dec 03 Python
python可视化 matplotlib画图使用colorbar工具自定义颜色
Dec 07 Python
PyTorch 中的傅里叶卷积实现示例
Dec 11 Python
Python数据分析入门之教你怎么搭建环境
May 13 Python
基于python实现的百度音乐下载器python pyqt改进版(附代码)
Aug 05 #Python
使用coverage统计python web项目代码覆盖率的方法详解
Aug 05 #Python
基于python实现的百度新歌榜、热歌榜下载器(附代码)
Aug 05 #Python
selenium2.0中常用的python函数汇总
Aug 05 #Python
Django中使用CORS实现跨域请求过程解析
Aug 05 #Python
Flask使用Pyecharts在单个页面展示多个图表的方法
Aug 05 #Python
PyQt5基本控件使用详解:单选按钮、复选框、下拉框
Aug 05 #Python
You might like
一个用mysql_odbc和php写的serach数据库程序
2006/10/09 PHP
PHP大转盘中奖概率算法实例
2014/10/21 PHP
PHP连接SQLServer2005的方法
2015/01/27 PHP
PHP flush 函数使用注意事项
2016/08/26 PHP
js类中获取外部函数名的方法与代码
2007/09/12 Javascript
用tip解决Ext列宽度不够的问题
2008/12/13 Javascript
ajax 缓存 问题 requestheader
2010/08/01 Javascript
使用js在页面中绘制表格核心代码
2013/09/16 Javascript
JavaScript中实现异步编程模式的4种方法
2014/09/24 Javascript
分享十五款 jQuery 社交网络分享插件
2015/05/16 Javascript
深入分析下javascript中的[]()+!
2015/07/07 Javascript
javascript控制层显示或隐藏的方法
2015/07/22 Javascript
移动手机APP手指滑动切换图片特效附源码下载
2015/11/30 Javascript
原生js实现移动端瀑布流式代码示例
2015/12/18 Javascript
BootStrap文件上传样式超好看【持续更新】
2016/05/10 Javascript
vue中如何引入jQuery和Bootstrap
2017/04/10 jQuery
JavaScript中各数制转换全面总结
2017/08/21 Javascript
Openlayers3实现车辆轨迹回放功能
2020/09/29 Javascript
JS页面动态绘图工具SVG,Canvas,VML介简介
2020/10/16 Javascript
vue实现简单加法计算器
2020/10/22 Javascript
[02:43]中国五虎出征TI3视频
2013/08/02 DOTA
批量获取及验证HTTP代理的Python脚本
2017/04/23 Python
Python创建普通菜单示例【基于win32ui模块】
2018/05/09 Python
python实时监控cpu小工具
2018/06/21 Python
django+echart数据动态显示的例子
2019/08/12 Python
python 负数取模运算实例
2020/06/03 Python
使用css创建三角形 使用CSS3创建3d四面体原理及代码(html5实践)
2013/01/06 HTML / CSS
Weblogic和WebSphere不同特点
2012/05/09 面试题
项目考察欢迎辞
2014/01/17 职场文书
2014年最新学习全国两会精神心得
2014/03/17 职场文书
校企合作协议书
2014/04/16 职场文书
4S店收银员岗位职责
2015/04/07 职场文书
2015年乡镇工会工作总结
2015/05/19 职场文书
入党介绍人考察意见
2015/06/01 职场文书
军训后的感想
2015/08/07 职场文书
如何计划开一家便利店?
2019/07/31 职场文书