您的位置:首页 > 产品设计 > UI/UE

数据分析——以斗鱼为实例解析requests库与scrapy框架爬虫技术

2017-11-08 02:23 1321 查看
按照我的理解,数据分析大概整体分为5大模块——数据收集、数据清洗、数据挖掘、数据建模、数据应用。

今天,我便“开车”进军第一大模块!数据收集!!!!

数据收集,通俗一点即爬虫技术,即利用脚本模拟浏览器行为向服务器发送请求并快速获取数据的过程。利用Python可以十分简单的制作一个爬虫(随便一搜,代码就哗哗嘀),因此我在这里就不赘述如何去写一个简单的爬虫了。这篇文章我将倾向于如何分别利用requests库和scrapy框架去完成相同数据的爬取,让大家看到两种方法各自的优缺点,尽量通俗易懂的为大家说明,我选取的是爬取斗鱼直播平台中主播的图片。

注:有任何问题,也欢迎大家在下面留言,随时与我交流。好啦,接下来开始开车啦!

一、requests库爬取斗鱼主播图片

1、requests库操作简介

1)session:开启会话。一般首先均会开启会话,并在会话上进行操作。

2)get(url, params=None):获取网页,允许使用params关键字,即支持以字典格式传递参数。其下常用的有:

.url:获取请求的url

.text:获取响应内容

.status_code:返回请求状态码;如 200表示成功,404表示用户端错误等。

.json:返回的内容转换为dict格式。

.encoding:返回响应内容的编码格式,也可以直接对其赋值改变编码格式。

.headers:返回响应头内容。

.cookies:返回cookies内容。

3)post(url, data, json):发送请求。若数据为字典,则用data参数传;若为json,则用json参数传。

注:字典与json可用json.dump()转换,不知道的同学可以去大致学习一下json库中的dumps与loads。

具体代码如下:

#coding=utf-8
import requests
import os
import json

s = requests.session()

offset = 0

url = "http://capi.douyucdn.cn/api/v1/getVerticalRoom?limit=20&offset=" + str(offset)

htmltext = s.get(url).text

htmltext = json.loads(htmltext.encode("utf-8"))

while True:

if len(htmltext['data']) != 0 :

for data in htmltext['data']:
nickname = data['nickname']
f = open("./Image/" + nickname + ".jpg", "w")
imageLink = data['vertical_src']
f.write(s.get(imageLink).content)

offset += 20
url = "http://capi.douyucdn.cn/api/v1/getVerticalRoom?limit=20&offset=" + str(offset)
htmltext = s.get(url).text

htmltext = json.loads(htmltext.encode("utf-8"))
else:
break
代码实现的内容十分简单,即爬取图片与主播名,将主播名作为图片名保存到本地文件中即可。

二、scrapy框架爬取斗鱼主播图片

1、scrapy结构简单讲解

Scrapy框架是专门的爬虫框架。所谓框架即已经有人为大家写好了大致的模板,而我们只需要填写一些我们所需的东西,即可以随心使用啦!听上去是不是很爽?感觉很方便咧?接下来跟着我,来看看scrapy是个什么鬼吧!如果没有scrapy基础的,一定要认认真真看下面的介绍,相信你能对scrapy有个初步认识。

Scrapy的整体结构如下:



第一眼看上去你肯定和当初的我一样懵逼!这尼玛是个什么东西?僵尸符嘛嘛嘛嘛嘛!!!不要慌!我下面这段解释很重要:

上图即Scrapy的主要结构:首先,scrapy解析器会从Spiders文件出发,将里面的请求交给Scheduler,然后Scheduler将请求给Downloader去下载,将下载到的数据再交还给Spiders。根据咱们自己所写的Spiders文件,将我们需要的数据交给Item Pipeline保存,如果在Spider文件中还有别的请求(爬取到的请求或者原始你就有很多要爬取的网站),Spider便再将这些请求给Scheduler,又开始了上面的循环,直到所有请求结束。

敲黑板! 



敲黑板!!!有很多同学混乱是因为他不知道调度器和引擎是什么,其实咱们并不用知道那是什么,因为这两个东西在你写scrapy时基本不会出现,所以你要知道的就只是我上面的解释即可!完全够写scrapy用的啦!

爬虫创建:用 scrapy startproject XXX 命令,在相对应的路径下创建一个名为XXX的scrapy框架。再输入scrapy
genspider XXX 域名,完成爬虫的创建,其中XXX为爬虫名,域名即为爬取的目标网站。 

2、scrapy各文件编写

1)编写item.py文件:明确想要爬取的数据,即你想爬取哪些内容要在item.py文件中说明。下面是我写的例子:

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html 
import scrapy

class DouyuItem(scrapy.Item):
nickname = scrapy.Field()
vertical_src = scrapy.Field()
由于我只要保存主播名称与图片的url地址,所以只要在item.py文件中声明这两个变量即可。(vertical_src中存的就是图片的url,别打我!!因为斗鱼用的就是这个变量名,所以我才会用的,真的不是我的锅!!



)
2)编写spider.py文件:在文件中处理请求和响应,以及提取所需要的数据。下面是例子咯:

# -*- coding: utf-8 -*-

import scrapy
from Douyu.items import DouyuItem
import json

class DouyuSpider(scrapy.Spider):
name = 'douyu'
allowed_domains = ['http://www.douyu.com']
base_url = 'http://capi.douyucdn.cn/api/v1/getVerticalRoom?limit=20&offset='
offset = 0
start_urls = [base_url + str(offset)]

def parse(self, response):
data_list = json.loads(response.body)["data"]
if len(data_list) == 0:
return
for data in data_list:
item = DouyuItem()
item['nickname'] = data['nickname'].encode("utf-8")
item['vertical_src'] = data['vertical_src']
yield item

self.offset += 20
url = self.base_url + str(self.offset)
yield scrapy.Request(url, callback=self.parse,dont_filter=True)
可以看到,具体流程就是去爬取,然后存取,存取的时候要yield item,这样才会调用刚刚编写的item.py文件来存取响   应内容;另外,yield是相当神奇的命令,他会返回数据,但是当下次再运行该函数时,函数会从yield语句后面继续运行。 
 另外就是当一页的数据爬取完以后,我们改变偏移量,实现翻页,然后利用yield scrapy.Request()方法继续请求,直到该   页数据为空才停止。

注:当后面所要数据不同于前面时,自己定义解析函数并在callback中改变解析函数即可。dont_filter是停止内部过滤,   否则可能会出一些小bug。
3)编写pipelines.py:处理spider返回的item数据。老规矩,下面是例子:
# -*- coding: utf-8 -*-

import scrapy
from scrapy.pipelines.images import ImagesPipeline
import os

class DouyuPipeline(ImagesPipeline):
def get_media_requests(self, item, info):
image_link = item['vertical_src']
yield scrapy.Request(image_link)

def item_completed(self, result, item, info):
path = '/Users/yixiong_bian/Desktop/Douyu主播图片爬取/Douyu/Image/'
if result[0][0] == True:
os.rename(path + result[0][1]['path'], path + str(item['nickname'] + ".jpg"))
return item
完成赋值与请求图片url;item_completed()方法是为了存储时完成对图片的重命名。在其中result变量下存着:   
   True/False, 图片url,图片存储的path,MD5码,修改其中的path即可实现重命名。
4)编写settings.py:存放各种设置的文件。如开启管道、设置管道优先级、禁用机器人协议、指定图片存放地址等。例子:
BOT_NAME = 'Douyu'

SPIDER_MODULES = ['Douyu.spiders']
NEWSPIDER_MODULE = 'Douyu.spiders'

IMAGES_STORE = '/Users/yixiong_bian/Desktop/Douyu主播图片爬取/Douyu/Image'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# item pipelines
ITEM_PIPELINES = {
'Douyu.pipelines.DouyuPipeline': 300,
}


上面就是我编写的scrapy框架的例子,值得注意的是:上面介绍的顺序就是一般scrapy开发时候文件编写的顺序。我写的也十分简单,没有加入中间件之类的操作。有什么问题欢迎提出,大家共同进步。

敲黑板!



注意啦!注意啦!:
爬取数据的流程一般为:利用网页解析器找网页源码规律 ---> 用python获取网页源码 ---> 解析出我们所需数据 ---> 保存
这种方法没有错误,但是每次都要获取数千行的网页源码并解析,这样的爬取效率太慢。应学会利用接口或网页解析器中的  network,找到数据关键性文件的url,从该数据文件中解析,速度会快相当多!!!!我这次爬取斗鱼就利用的斗鱼的api,你们  有兴趣的话可以试试从网站上爬取,然后对比一下效率。

三、requests与scrapy对比

从上面例子不难看出,scrapy的代码量与复杂程度远远高于requests,那么我们为什么还要学习用scrapy这个东西呢?没错!估计聪明的你已经有了答案,那就是scrapy的爬取速度要远远高于requests库,我曾经用scrapy和requests库对豆瓣电影进行爬取,下面分别是scrapy与requests库的运行时间:





即使用了多进程、多线程加速,爬取时间仍然与scrapy有差距:



  


最后,我来总结一下scrapy与requests库各自的优缺点:
scrapy:
优点:爬取速度特快,快的令人发指。
缺点:代码复杂度较高,不适合爬取动态网页。
requests:
优点:方法简单,代码量少,入门方便。
缺点:爬取速度较慢,即使运用加速,仍与scrapy差距较大,也不太适合动态网页爬取。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息