这里是通过爬取伯乐在线的全部文章为例子,让自己先对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. FR嵌套报表(Nested Report)

    //主界面只是说明放置了哪些东西(3个ADOQuery不必放): //MasterSource.MasterField的设置如下: 1) Customer.Orders.Items 的 MasterS ...

  2. C#数据结构与算法系列(四):链表——单链表(Single-LinkedList)

    1.介绍: 链表是有序的列表,但是它在内存的存储如下:  链表是以节点的方式来存储,链式存储 每一个节点包含data域,next域:指向下一个节点 链表的各个节点不一定是连续存储 链表分带头节点的链表 ...

  3. TensorFlow从0到1之XLA加速线性代数编译器(9)

    加速线性代数器(Accelerated linear algebra,XLA)是线性代数领域的专用编译器.根据 https://www.tensorflow.org/performance/xla/, ...

  4. Spring Boot入门系列(十八)整合mybatis,使用注解的方式实现增删改查

    之前介绍了Spring Boot 整合mybatis 使用xml配置的方式实现增删改查,还介绍了自定义mapper 实现复杂多表关联查询.虽然目前 mybatis 使用xml 配置的方式 已经极大减轻 ...

  5. 淘宝官网css初始化

    body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend ...

  6. 《Java并发编程的艺术》 第9章 Java中的线程池

    第9章 Java中的线程池 在开发过程中,合理地使用线程池能带来3个好处: 降低资源消耗.通过重复利用已创建的线程 降低线程创建和销毁造成的消耗. 提高响应速度.当任务到达时,任务可以不需要等到线程创 ...

  7. C++_继承

    C++支持单继承和多继承,并提供3类继承:public.private及protected.在public继承中,每个派生类对象都是基类对象,反之基类对象却不是派生类对象.派生类成员无法直接访问基本的 ...

  8. 3、尚硅谷_SSM高级整合_使用ajax操作实现修改员工的功能

    当我们点击编辑案例的时候,我们要弹出一个修改联系人的模态对话框,在上面可以修改对应的联系人的信息 这里我们我们要编辑按钮添加点击事件弹出对话框 第一步:在页面中在新增一个编辑联系人的模态对话框 第二步 ...

  9. IDEA解决SVN频繁弹出登录框

    将HTTP请求改成SVN就可以了,或者请项目经理开启SVN中的HTTP请求

  10. HTML&CSS面试高频考点(一)

    1. 行内元素/块级元素 非替换元素/替换元素 行内元素(内联元素):a, abbr(缩写), acronym(只取首字母缩写), b, bdo(文本方向), big, br, cite(引用), c ...