这里是通过爬取伯乐在线的全部文章为例子,让自己先对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基础配置

创建项目命令:python3 -m scrapy startproject test1

下面直接分析爬虫代码

代码的项目结构

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

1-----Scrapy框架整体的一个了解的更多相关文章

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

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

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

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

  3. scrapy框架系列 (2) 一个简单案例

    学习目标 创建一个Scrapy项目 定义提取的结构化数据(Item) 编写爬取网站的 Spider 并提取出结构化数据(Item) 编写 Item Pipelines 来存储提取到的Item(即结构化 ...

  4. Scrapy框架-scrapy框架架构详解

    1.Scrapy框架介绍 写一个爬虫,需要做很多的事情.比如:发送网络请求.数据解析.数据存储.反反爬虫机制(更换ip代理.设置请求头等).异步请求等.这些工作如果每次都要自己从零开始写的话,比较浪费 ...

  5. scrapy框架(三)

    scrapy框架(三) CrawlSpider类 创建CrawlSpider  # 创建项目后 $ scrapy genspider -t crawl spider_name website_doma ...

  6. 网络爬虫第五章之Scrapy框架

    第一节:Scrapy框架架构 Scrapy框架介绍 写一个爬虫,需要做很多的事情.比如:发送网络请求.数据解析.数据存储.反反爬虫机制(更换ip代理.设置请求头等).异步请求等.这些工作如果每次都要自 ...

  7. 一个scrapy框架的爬虫(爬取京东图书)

    我们的这个爬虫设计来爬取京东图书(jd.com). scrapy框架相信大家比较了解了.里面有很多复杂的机制,超出本文的范围. 1.爬虫spider tips: 1.xpath的语法比较坑,但是你可以 ...

  8. 爬虫之scrapy框架

    解析 Scrapy解释 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓 ...

  9. Scrapy框架

    Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以 ...

随机推荐

  1. ElasticSearch 入门(转)

    最大的特点: 1. 数据库的 database, 就是  index 2. 数据库的 table,  就是 tag 3. 不要使用browser, 使用curl来进行客户端操作.  否则会出现 jav ...

  2. loj10098 分离的路径

    传送门 分析 此题要先用tarjan求点双联通分量,注意在求解是要注意一条无向边只能走一次.求完之后我们发现原来的图会变成一棵树,对于 这棵树我们发现答案是(叶子节点数量+1)/2,实际便是每两个节点 ...

  3. cakephp增删改查

    增 $this->create(); $ret = $this->save($data); 删 $ret = $this->deleteAll(array('user_id'=> ...

  4. rest-framework组件 之 分页

    分页 简单分页 from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination class PNPag ...

  5. Entity Framework Tutorial Basics(39):Raw SQL Query

    Execute Native SQL Query You can execute native raw SQL query against the database using DBContext. ...

  6. epoll聊天室的实现

    1.服务端 a. 支持多个用户接入,实现聊天室的基本功能 b. 使用epoll机制实现并发,增加效率 2. 客户端 a. 支持用户输入聊天消息 b. 显示其他用户输入的信息 c. 使用fork创建两个 ...

  7. Windows7 安装TensorFlow(本人试了好多方法后的成果)

    本人机器为64位win7 首先安装python,版本一定要注意,TennsorFlow要使用 Python3.0 系列版本不能使用2.0系列版本,但是TensorFlow 的安装包目前windows版 ...

  8. [转]JQ中$(window).load和$(document).ready区别与执行顺序

    一.$(window).load().window.onload=function(){}和$(document).ready()方法的区别 1.$(window).load() 和window.on ...

  9. win8使用every'thing无法显示搜索结果的解决方法

    关键词: win8,everything,无搜索结果 进入everything ,tools->option右下角有个 restore defaults 如果安全软件阻拦,点击  允许 就行了, ...

  10. pthread中如何追踪stack over flow

    通常在程序挂掉的时候我们会catch 他们挂掉的signal,然后在signal中打印出当时的一个stack,来方便问题调查, 但是在stack overflow的情况发生时,会没有拿到stack.s ...