为了账号安全,请及时绑定邮箱和手机立即绑定
慕课专栏

目录

索引目录

Python 数据分析通关攻略

原价 ¥ 58.00

立即订阅
03 数据准备篇:没有数据怎么办,当然自己爬喽
更新时间:2019-12-17 08:13:20
智慧,不是死的默念,而是生的沉思。

——斯宾诺莎

俗话说:将军难打无兵之仗,巧妇难为无米之炊。意思就是说,专业技能和素养都具备了,但是没有对应的资源供你调度,那也是空有一身本领而难倒英雄汉。

对于数据分析,特别是在入门阶段,如果没有对应的数据供练习实战,那终归会停留在纸上谈兵阶段而无法知悉代码背后的秘密。模拟真实数据分析场景至关重要,但是数据又该从何而来呢?

作为程序员,开源使人进步。开源的数据库同样如此,这里力荐几个公开数据集供大家选择:

开源数据国外篇

  • GitHub awesome-public-datasets

awesome-public-datasets(https://github.com/awesomedata/awesome-public-datasets),一个GitHub上开源的数据资源库,涉及到的领域涵盖了农业、生物学、气候、计算机网络、数据科学、地球科学、经济学、教育、能源、金融学、地图、图像处理、机器学习、自然语言、神经科学、物理学、心理学、社会科学…

图片描述

  • 亚马逊跨学科数据平台

图片描述

开源数据国内篇

  • 国家数据National Data

图片描述

  • 国家统计局数据

图片描述

国家统计局官网的底部,预留了各个地方、其他国家、国际组织的官方链接,有兴趣的朋友也可以去这里淘金。

定向网站的数据采集

但是对于更一般的场景,部分朋友希望能够采集到更加专业的信息。比如想研究股票信息,需要去股票网站采集交易、价格等数据;想研究房地产信息,可以去链家、贝壳等网站采集买卖详单;想要研究社会舆情,可以去新闻门户网站采集新闻类信息。

数据量太大怎么办?门户网站没有提供下载链接。对于已经学习了Python的朋友们来讲,没有技术解决不了的问题,如果有,那就是技术还需要操练。

这里我们提供两种解决方案:

  • 八爪鱼在线定向采集网站

图片描述

  • 编写个人爬虫程序

如果上面的手段都解决不了问题,那么只有祭出我们终极武器啦——编写爬虫程序。

八爪鱼也是一款可轻度定制的爬虫程序,只不过为了适应更广的应用需求,智能程度以及采集效率并不高,而且无法完成一些深入的定制。对付简单任务还行,对付稍微复杂的任务,要么付费,要么歇菜了。

其实爬虫并没有那么神秘,简单来说,爬虫就是一款可重复对目标网站进行数据采集的轻量级程序。比如,我想采集北京正在热映的电影清单,我们打开豆瓣北京的首页(https://movie.douban.com/cinema/nowplaying/beijing/),可以看到如下:

图片描述

我希望开发一个程序,能够一键采集这个网页上的信息,包括电影名称,电影评分,以及影片图片链接。

在正式开始我们的爬虫之前,我们先来探讨一个问题,什么是浏览器?官方给的定义是,一种用于检索并展示web信息资源的应用程序。在我们浏览豆瓣-北京首页的时候,豆瓣服务器根据已经建立的数据传输链路,把电影的信息传递给我们的本地电脑。在本地获取到这些信息后,浏览器通过一定的规则,或重排版,或解码,最终解析成为我们看到的这个样子(见上图)。

那爬虫呢?爬虫就是自动到网页上去采集我们需要的信息?这个表述并不准确。爬虫是我们利用Python搭建的一个网络应用服务,它把自己伪装成浏览器,向目标服务器发送请求,并与之建立数据传输的链路。但是与普通浏览器不同的是,爬虫只会解析网站中我们关注的信息,并保存起来(或者直接打印),其他的弃之不用。

所以从这角度看,简单爬虫可以分为三个关键步骤,1)伪装成浏览器,从目标服务器获取想要的数据;2)建立解析规则,从上一步获取的数据中解析出关注的信息;3)打印或保存。

伪装成浏览器,从目标服务器获取想要的数据

在这之前,我们先看一下,我们经常浏览的网页页面的真实面目。这里我以Chrome为例,做一个演示。

点击Chrome的折叠菜单,继续选择更多工具 > 开发者工具,在跳出的隐藏页面中,选择Elements菜单,示意如下:

图片描述

因此,第一步我们的目标,就是先通过Python,构建一个简单应用,并成功抓取网页的页面内容。这里给大家介绍一个工具requests,这个工具通过简单的命令就可以模仿浏览器向服务器发送get请求,并反馈服务器的返回数据。requests可以通过PIP工具快速安装:

C:\Users\Administrator>pip install requests

完成安装后,我们做一个简单测试,在Notebook中输入:

# 导包
import requests
# url为目标网址
url = "https://movie.douban.com/cinema/nowplaying/beijing/"
# 通过requests库,发起一个url请求。把目标服务器的返回值赋值给response
response = requests.get(url)
# text为response的属性,表示返回值的正文内容
print(response.text)
Out:(仅显示部分关键信息,供参考)
<!DOCTYPE html>
……    
……
……
    <li
        id="30481973"
        class="list-item"
        data-title="决胜时刻"
        data-score="7.1"
        data-star="35"
        data-release="2019"
        data-duration="140分钟"
        data-region="中国大陆"
        data-director="黄建新 宁海强"
        data-actors="唐国强 / 刘劲 / 黄景瑜"
        data-category="nowplaying"
        data-enough="True"
        data-showed="True"
        data-votecount="3581"
        data-subject="30481973"
        >
        <ul class="">
            <li class="poster">
                <a href="https://movie.douban.com/subject/30481973/?from=playing_poster" class=ticket-btn target="_blank" data-psource="poster">
                    <img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2568497857.jpg" alt="决胜时刻" rel="nofollow" class="" />
                </a>

    ……    

从上面的请求内容可以看到电影名称:决胜时刻,主演:唐国强 / 刘劲 / 黄景瑜,导演:黄建新 宁海强等信息。

到这里呢,第一步中最关键的一步基本完成,但是还要做一些简单的包装。

我们都知道,如果网页打不开了,常常会看到浏览器返回404 not found。这里的404表示的是状态码,说明这个链接失效了。那如果网页是正常的呢,网页返回的状态码是200。因此我们做一个简单的判断,如果网页一切正常(状态码200),则返回网页的内容(字符串类型);如果网页不正常(状态码不是200),则返回None,防止程序报错。

# 这里是requests自带的一个请求异常错误
from requests import RequestException

# 封装一个名为get_page的函数,用来获取网页的内容,以文本形式返回。如果网页状态码不为200,则返回空值
# 若是请求异常,同样返回空值
def get_page(url):
    try:
        response = requests.get(url)
        if response.status_code == 200:
            return response.text
        return None
    except RequestException:
        return None
url = "https://movie.douban.com/cinema/nowplaying/beijing/"
html = get_page(url)
html

依次执行这两步程序,可以打印出页面的内容。效果这里就不展示了,请大家自行实践。

建立解析规则,从上一步获取的数据中解析出关注的信息

在不借助外力的情况下,从一大长串字符串中提取目标信息,有什么方法?有经验的朋友一定能够猜到,用正则匹配。没错,这基本是一个万能的方法,但是比较考验基本功。

我们总览上一步得到的html的打印值,一定可以找到电影的信息都放在<li>以及<img> 2 个标签中,那我们就是写一个正则,把这2个标签中,我们想要的电影名称、电影评分、电影图片超链接提取出来。但是这里要注意几个问题:

从打印值可以看出,字符串是换行的,正则需要跨行匹配。我们在匹配语句中加上re.S就可以了;

一共有几十个电影名录,那就说明每一个电影都有和其对应的<li>标签以及<img>标签。因此我们需要抑制正则匹配的贪婪性。即只匹配最近字符,做最小匹配。我们用.*表示匹配任意字符尽可能多的次数,用.*?表示最小匹配任意字符;

分析到这里,一切基本明了了,剩下就是写的问题了。

# 导入正则包
import re
# 根据上面的分析过程,构建匹配规则。其中()表示分组,并按照分组输出匹配结果
pattern = re.compile('<li.*?list-item.*?data-title="(.*?)".*?data-score="(.*?)".*?>.*?<img.*?class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="(.*?)".*?/>', re.S)
# 用findall函数进行规则与字符串的匹配,并按照顺序返回全部的匹配结果,返回结果为list类型
items = re.findall(pattern, html)
# 打印items的变量类型,在notebook中,print()可以省略
type(items)
Out: list
len(items)
Out: 64
items[0]
Out:
    ('决胜时刻',
     '7.1',
     'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2568497857.jpg')

从执行结果可以看出来,一共匹配上了64个结果,其中第一个结果我们做了打印预览,从items[0]的结果看,这应该是个元祖。

解析过程基本分析清楚了,我们构建一个函数来封装这个规则解析过程,其中函数的输入是html网页内容,输出是匹配的结果。

# 对网页文本内容进行解析。封装一个名为parse_page的函数,用正则来解析HTML。
def parse_page(html):
    pattern = re.compile('<li.*?list-item.*?data-title="(.*?)".*?data-score="(.*?)".*?>.*?<img.*?class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="(.*?)".*?/>', re.S)
    items = re.findall(pattern, html)
    
    # 通过上一步的测试,我们知道了items长度为64。为了优化内存,这里构建了一个迭代器,在下一步打印的时候,有for循环来读取这个迭代器
    for item in items:
        yield{
            'title': item[0],
            'score': item[1],
            'image': item[2],}

打印预览

构建一个循环,逐个打印输出结果:

for item in parse_page(html):
    print(item)
Out:
    {'title': '决胜时刻', 'score': '7.1', 'image': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2568497857.jpg'}
	{'title': '小Q', 'score': '7.0', 'image': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2566474488.jpg'}
    {'title': '友情以上', 'score': '6.6', 'image': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2565511423.jpg'}
    {'title': '罗小黑战记', 'score': '8.2', 'image': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2568288336.jpg'}
    ……
    {'title': '红色娘子军', 'score': '7.2', 'image': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2044374611.jpg'}
	{'title': '五朵金花', 'score': '8.0', 'image': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2529223569.jpg'}

整个爬虫的流程到这里就分析结束了,是不是很简单?程序完整的demo放在了1-1小节,朋友们可以翻看查看。用这个思路,朋友们去采集一些简单的网站,比如大部分政府网站、豆瓣、链家等等,都是没有问题的。

当然了,今天只是浅尝辄止,爬虫可以还有很多内容需要去学习,比如如何绕过反爬策略,如何高效地解析网页,如何保存,如何批量爬取等等。本门专栏聚焦在数据分析与处理,我们如何利用爬虫爬到的数据,做进一步的总结。专栏用到的数据都是来自于公开的互联网,数据会放在公有云上供大家免费下载学习,提高大家学习的效率。

总结

数据对于分析师,就好比食材对于厨师,只有上好的食材,做出来的食物才甜美可口。那如何获得上等的数据呢,可以从开源数据下载,可以用商用的采集器比如八爪鱼采集,当然也可以自己动手设计爬虫采集。对于每一种途径,本文都提供了相应的渠道供朋友们使用。

对于新入门的朋友们,需要注重于对数据分析逻辑的理解和常用技巧的掌握。在后续每个章节,我讲解完基础语法后,都会配以一定的实战demo。朋友们在熟悉这些技巧之后,也可以从国内外(优先推荐国内,因为更加贴近生活)的开源数据库中,下载数据进行数据清洗和可视化,增加实战经验。

爬虫则常常应用于于深度定制的专题化数据需求,朋友们在兴趣和经验的基础上,可以多做一些有益的尝试。

}
立即订阅 ¥ 58.00

你正在阅读课程试读内容,订阅后解锁课程全部内容

千学不如一看,千看不如一练

手机
阅读

扫一扫 手机阅读

Python 数据分析通关攻略
立即订阅 ¥ 58.00

举报

0/150
提交
取消