这里是通过爬取伯乐在线的全部文章为例子,让自己先对scrapy进行一个整理的理解

该例子中的详细代码会放到我的github地址:https://github.com/pythonsite/spider/tree/master/jobboleSpider

注:这个文章并不会对详细的用法进行讲解,是为了让对scrapy各个功能有个了解,建立整体的印象。

在学习Scrapy框架之前,我们先通过一个实际的爬虫例子来理解,后面我们会对每个功能进行详细的理解。
这里的例子是爬取http://blog.jobbole.com/all-posts/ 伯乐在线的全部文章数据

分析要爬去的目标站信息

先看如下图,首先我们要获取下图中所有文章的连接,然后是进入每个文章连接爬取每个文章的详细内容。
每个文章中需要爬取文章标题,发表日期,以及标签,赞赏收藏,评论数,文章内容。

对于该爬虫的一个整体思路

我们对这个爬虫进行一个思路整理,通过如下图表示:

以上是我们对这个爬虫需求了解,下面我们通过scrapy爬取我们想要爬取的数据,下面我们先对scrapy进行一个简单的了解

Scrapy的初步认识

Scrapy使用了Twisted作为框架,Twisted有些特殊的地方是它是事件驱动的,并且比较适合异步的代码。对于会阻塞线程的操作包含访问文件、数据库或者Web、产生新的进程并需要处理新进程的输出(如运行shell命令)、执行系统层次操作的代码(如等待系统队列),Twisted提供了允许执行上面的操作但不会阻塞代码执行的方法。
scrapy的项目结构:

items.py 负责数据模型的建立,类似于实体类。
middlewares.py 自己定义的中间件。
pipelines.py 负责对spider返回数据的处理。
settings.py 负责对整个爬虫的配置。
spiders目录 负责存放继承自scrapy的爬虫类。
scrapy.cfg scrapy基础配置

那么如何创建上述的目录,通过下面命令:

zhaofandeMBP:python_project zhaofan$ scrapy startproject test1
New Scrapy project 'test1', using template directory '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/scrapy/templates/project', created in:
/Users/zhaofan/Documents/python_project/test1 You can start your first spider with:
cd test1
scrapy genspider example example.com
zhaofandeMBP:python_project zhaofan$
zhaofandeMBP:test1 zhaofan$ scrapy genspider shSpider hshfy.sh.cn
Created spider 'shSpider' using template 'basic' in module:
test1.spiders.shSpider

相信上面这段话你肯定会觉得很无聊,所以直接分析爬虫代码。

代码的项目结构

items.py代码分析

items.py里存放的是我们要爬取数据的字段信息,代码如下:
我们分别要爬取的信息包括:文章标题,文件发布时间,文章url地址,url_object_id是我们会对地址进行md5加密,front_image_url 是文章下图片的url地址,front_image_path图片的存放路径

class JoBoleArticleItem(scrapy.Item):
title = scrapy.Field()
create_date = scrapy.Field()
url = scrapy.Field()
url_object_id = scrapy.Field()
front_image_url = scrapy.Field()
front_image_path = scrapy.Field()
praise_nums = scrapy.Field()
fav_nums = scrapy.Field()
comment_nums = scrapy.Field()
tag = scrapy.Field()
content = scrapy.Field()

spiders/Article.py代码分析

spiders目录下的Article.py为主要的爬虫代码,包括了对页面的请求以及页面的处理,这里有几个知识点需要注意:
这些知识点我会在后面详细写一个文章整理,这里先有一个初步的印象。

1. 我们爬取的页面时http://blog.jobbole.com/all-posts/,所以parse的response,返回的是这个页面的信息,但是我们这个时候需要的是获取每个文章的地址继续访问,这里就用到了yield Request()这种用法,可以把获取到文章的url地址继续传递进来再次进行请求。
2. scrapy提供了response.css这种的css选择器以及response.xpath的xpath选择器方法,我们可以根据自己的需求获取我们想要的字段信息

class ArticleSpider(scrapy.Spider):
name = "Article"
allowed_domains = ["blog.jobbole.com"]
start_urls = ['http://blog.jobbole.com/all-posts/'] def parse(self, response):
'''
1.获取文章列表也中具体文章url,并交给scrapy进行下载后并进行解析
2.获取下一页的url并交给scrapy进行下载,下载完成后,交给parse
:param response:
:return:
'''
#解析列表页中所有文章的url,并交给scrapy下载后进行解析
post_nodes = response.css("#archive .floated-thumb .post-thumb a")
for post_node in post_nodes:
#image_url是图片的地址
image_url = post_node.css("img::attr(src)").extract_first("")
post_url = post_node.css("::attr(href)").extract_first("")
#这里通过meta参数将图片的url传递进来,这里用parse.urljoin的好处是如果有域名我前面的response.url不生效
# 如果没有就会把response.url和post_url做拼接
yield Request(url=parse.urljoin(response.url,post_url),meta={"front_image_url":parse.urljoin(response.url,image_url)},callback=self.parse_detail) #提取下一页并交给scrapy下载
next_url = response.css(".next.page-numbers::attr(href)").extract_first("")
if next_url:
yield Request(url=next_url,callback=self.parse) def parse_detail(self,response):
'''
获取文章的详细内容
:param response:
:return:
'''
article_item = JoBoleArticleItem() front_image_url = response.meta.get("front_image_url","") #文章封面图地址
title = response.xpath('//div[@class="entry-header"]/h1/text()').extract_first() create_date = response.xpath('//p[@class="entry-meta-hide-on-mobile"]/text()').extract()[0].strip().split()[0] tag_list = response.xpath('//p[@class="entry-meta-hide-on-mobile"]/a/text()').extract()
tag_list = [element for element in tag_list if not element.strip().endswith("评论")]
tag =",".join(tag_list)
praise_nums = response.xpath('//span[contains(@class,"vote-post-up")]/h10/text()').extract()
if len(praise_nums) == 0:
praise_nums = 0
else:
praise_nums = int(praise_nums[0])
fav_nums = response.xpath('//span[contains(@class,"bookmark-btn")]/text()').extract()[0]
match_re = re.match(".*(\d+).*",fav_nums)
if match_re:
fav_nums = int(match_re.group(1))
else:
fav_nums = 0 comment_nums =response.xpath("//a[@href='#article-comment']/span/text()").extract()[0]
match_com = re.match(".*(\d+).*",comment_nums)
if match_com:
comment_nums = int(match_com.group(1))
else:
comment_nums=0 content = response.xpath('//div[@class="entry"]').extract()[0] article_item["url_object_id"] = get_md5(response.url) #这里对地址进行了md5变成定长
article_item["title"] = title
article_item["url"] = response.url
try:
create_date = datetime.datetime.strptime(create_date,'%Y/%m/%d').date()
except Exception as e:
create_date = datetime.datetime.now().date() article_item["create_date"] = create_date
article_item["front_image_url"] = [front_image_url]
article_item["praise_nums"] = int(praise_nums)
article_item["fav_nums"] = fav_nums
article_item["comment_nums"] = comment_nums
article_item["tag"] = tag
article_item['content'] = content yield article_item

pipeline中代码的分析

pipeline主要是对spiders中爬虫的返回的数据的处理,这里我们可以让写入到数据库,也可以让写入到文件等等。
下面代码中主要包括的写入到json文件以及写入到数据库,包括异步插入到数据库,还有图片的处理,这里我们可以定义各种我们需要的pipeline,当然这里我们不同的pipeline是有一定的顺序的,需要的设置是在settings配置文件中,如下,后面的数字表示的是优先级,数字越小优先级越高。

class JobbolespiderPipeline(object):
def process_item(self, item, spider):
return item class JsonWithEncodingPipeline(object):
'''
返回json数据到文件
'''
def __init__(self):
self.file = codecs.open("article.json",'w',encoding="utf-8") def process_item(self, item, spider):
lines = json.dumps(dict(item),ensure_ascii=False) + "\n"
self.file.write(lines)
return item def spider_closed(self,spider):
self.file.close() class MysqlPipeline(object):
'''
插入mysql数据库
'''
def __init__(self):
self.conn =pymysql.connect(host='192.168.1.19',port=3306,user='root',passwd='',db='article_spider',use_unicode=True, charset="utf8")
self.cursor = self.conn.cursor() def process_item(self,item,spider):
insert_sql = '''
insert into jobbole_article(title,create_date,url,url_object_id,front_image_url,front_image_path,comment_nums,fav_nums,praise_nums,tag,content) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
''' self.cursor.execute(insert_sql,(item["title"],item["create_date"],item["url"],item["url_object_id"],item["front_image_url"],item["front_image_path"],item["comment_nums"],item["fav_nums"],item["praise_nums"],item["tag"],item["content"]))
self.conn.commit() class MysqlTwistedPipline(object):
'''
采用异步的方式插入数据
'''
def __init__(self,dbpool):
self.dbpool = dbpool @classmethod
def from_settings(cls,settings):
dbparms = dict(
host = settings["MYSQL_HOST"],
port = settings["MYSQL_PORT"],
user = settings["MYSQL_USER"],
passwd = settings["MYSQL_PASSWD"],
db = settings["MYSQL_DB"],
use_unicode = True,
charset="utf8",
)
dbpool = adbapi.ConnectionPool("pymysql",**dbparms)
return cls(dbpool)
def process_item(self,item,spider):
'''
使用twisted将mysql插入变成异步
:param item:
:param spider:
:return:
'''
query = self.dbpool.runInteraction(self.do_insert,item)
query.addErrback(self.handle_error) def handle_error(self,failure):
#处理异步插入的异常
print(failure) def do_insert(self,cursor,item):
#具体插入数据
insert_sql = '''
insert into jobbole_article(title,create_date,url,url_object_id,front_image_url,front_image_path,comment_nums,fav_nums,praise_nums,tag,content) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
'''
cursor.execute(insert_sql,(item["title"],item["create_date"],item["url"],item["url_object_id"],item["front_image_url"],item["front_image_path"],item["comment_nums"],item["fav_nums"],item["praise_nums"],item["tag"],item["content"])) class ArticleImagePipeline(ImagesPipeline):
'''
对图片的处理
'''
def item_completed(self, results, item, info): for ok ,value in results:
if ok:
image_file_path = value["path"]
item['front_image_path'] = image_file_path
else:
item['front_image_path'] = "" return item

Python之爬虫从入门到放弃(十三) Scrapy框架整体的了解的更多相关文章

  1. Python爬虫从入门到放弃 之 Scrapy框架中Download Middleware用法

    这篇文章中写了常用的下载中间件的用法和例子.Downloader Middleware处理的过程主要在调度器发送requests请求的时候以及网页将response结果返回给spiders的时候,所以 ...

  2. Python爬虫从入门到放弃(十三)之 Scrapy框架的命令行详解

    这篇文章主要是对的scrapy命令行使用的一个介绍 创建爬虫项目 scrapy startproject 项目名例子如下: localhost:spider zhaofan$ scrapy start ...

  3. python爬虫从入门到放弃(八)之 Selenium库的使用

    一.什么是Selenium selenium 是一套完整的web应用程序测试系统,包含了测试的录制(selenium IDE),编写及运行(Selenium Remote Control)和测试的并行 ...

  4. Python爬虫从入门到放弃(十一)之 Scrapy框架整体的一个了解

    这里是通过爬取伯乐在线的全部文章为例子,让自己先对scrapy进行一个整理的理解 该例子中的详细代码会放到我的github地址:https://github.com/pythonsite/spider ...

  5. Python爬虫从入门到放弃(十二)之 Scrapy框架的架构和原理

    这一篇文章主要是为了对scrapy框架的工作流程以及各个组件功能的介绍 Scrapy目前已经可以很好的在python3上运行Scrapy使用了Twisted作为框架,Twisted有些特殊的地方是它是 ...

  6. python网络爬虫之入门[一]

    目录 前言 一.探讨什么是python网络爬虫? 二.一个针对于网络传输的抓包工具fiddler 三.学习request模块来爬取第一个网页 * 扩展内容(爬取top250的网页) 后记 @(目录) ...

  7. python爬虫入门(七)Scrapy框架之Spider类

    Spider类 Spider类定义了如何爬取某个(或某些)网站.包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item). 换句话说,Spider就是您定义爬取的动作 ...

  8. 爬虫入门(四)——Scrapy框架入门:使用Scrapy框架爬取全书网小说数据

    为了入门scrapy框架,昨天写了一个爬取静态小说网站的小程序 下面我们尝试爬取全书网中网游动漫类小说的书籍信息. 一.准备阶段 明确一下爬虫页面分析的思路: 对于书籍列表页:我们需要知道打开单本书籍 ...

  9. python 全栈开发,Day137(爬虫系列之第4章-scrapy框架)

    一.scrapy框架简介 1. 介绍 Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速.简单.可扩展的方式从网站中提取所需的数据.但目前S ...

随机推荐

  1. OpenSSH详解

    OpenSSH详解(思维导图) 1. SSH概述 SSH 软件架构 认证方式 2. OpenSSH 2.1 客户端程序ssh 配置文件 ssh命令 客户端免密登录 scp sftp 2.2 服务端程序 ...

  2. 在Xcode11上开发“面向低于iOS13版本的App”时的一些注意点

    相关知识: https://blog.csdn.net/BUG_delete/article/details/103699563 'AppDelegate' is only available in ...

  3. 写一个通用的List集合导出excel的通用方法

    前几天要做一个数据导出Excel 我就打算写一个通用的. 这样一来用的时候也方便,数据主要是通过Orm取的List.这样写一个通用的刚好. public static void ListToExcel ...

  4. WEB应用的常见安全漏洞

      01. SQL 注入 SQL 注入就是通过给 web 应用接口传入一些特殊字符,达到欺骗服务器执行恶意的 SQL 命令.SQL 注入漏洞属于后端的范畴,但前端也可做体验上的优化.原因:当使用外部不 ...

  5. MFC时间简单比较方法

    MFC//时间简单比较方法 void CMFCsaveListTofileDlg::OnBnClickedButton6()//时间简单比较方法 { // TODO: 在此添加控件通知处理程序代码 C ...

  6. ASP.NET WebAPI框架解析第一篇

    ASP.NET WebAPI有两种寄宿模式,一种是WebHost,一种是SelfHost,为什么可以有两种模式的原因在于WebAPI有一个相对独立的消息处理管道,只要给这个消息管道传递一个封装好的对象 ...

  7. java基础——并发1

    一.并发的定义 并发:对于这个概念一直就是没怎么搞懂,就是感觉特别的生疏,(自己从从字面上理解就是多个东西,一起出发),所以就上网上查了一些资料: 同时拥有两个或多个线程,如果程序在单核处理器上运行, ...

  8. SpringCloud教程第2篇:Ribbon(F版本)

    一.ribbon简介 Spring cloud有两种服务调用方式,一种是ribbon+restTemplate,另一种是feign.在这一篇文章首先讲解下基于ribbon+rest. ribbon是一 ...

  9. PV、UV、VV、IP的区别

    PV.UV.VV.IP的区别 PV即Page View,网站浏览量 指页面的浏览次数,用于衡量网站用户访问的网页数量.用户每次打开一个页面便记录1次PV,多次打开同一页面则浏览量累计. 一般来说,PV ...

  10. JavaScript基础有关构造函数、new关键字和this关键字(009)

    1. 总是记得用new关键字来执行构造函数.前面提到,可以用构造函数创建JavaScript的对象,这个构造函数在使用的时候需要使用new关键字,但如果忘记写入new关键字,会怎么样?事实上这个函数还 ...