从零开始写Python爬虫 --- 1.9 爬虫实践:悦音台mv排行榜与反爬虫技术

从零开始写Python爬虫 --- 1.9 爬虫实践:悦音台mv排行榜与反爬虫技术

这篇文章是 requests-bs4爬虫线路的最后一个章节了,我们这次要抓的是悦音台mv的排行榜,由于这个排行榜是实时更新的,如果要求我们不停地抓取,这将有可能导致悦音台官方采用反爬虫的技术将我们的ip给封了。所以这里也会捎带一点与反爬虫相关的知识:

目标分析:

看一下网址先:

http://vchart.yinyuetai.com/vchart/trends?area=ML


再看一下网站的结构:


我用红线圈出来的地方都是需要我们注意的小细节:

首先 排行榜分为,内地、港台、欧美、韩国、日本五个地区
我们分别将其点开能够观察到url的变化为在最尾部加了一个参数:area=地区参数

我们很容易的就能知道参数列表:['ML','HT','US','JP','KR'] 分别对应着内地、香港、欧美、日本、以及韩国。发现这个规律之后,我们只要通过简单的对url的变化就能多次请求,筛选出我们想要的信息

其次 我们发现,有的mv分数是呈现上升趋势,有的mv的分数是成下降趋势,这在网页的代码里又会有怎么样的体现呢?这里我留给大家自己观察一下。

最后,我们看到 这里mv的排行榜数据是实时更新的,所以我们的程序要不停的在后台运行才能保证我们获得的数据是最新的,这样就会引起官方人员的注意,他们的反爬虫技术有可能就会将我们的爬虫 “拒之门外” 我们要如何面对这种情况呢? 下文我会进行讲解

网页结构:

由于这是bs4线路的最后一个爬虫,在经历了这么多小demo的洗礼之后,我相信大家都能够通过自己的方式,定位到我们需要的元素,
我这里就不一一讲解了,还是那句话,能自己动手和动脑的,尽量去做,毕竟我们大多数人都没有“颅内编程”的实力。
另外,如果自己找不到,可以去我的Github看源代码,Github的链接放在文章末尾处。

结果展示:


反爬虫技术:

首先来介绍一下什么是反爬虫技术:

最近“大数据的兴起“,市面上出现了太多以数据分析为核心的创业公司,他们不仅要写出对数据操作分析的算法,更是要想方设法的获得大量的数据,这些数据从何而来呢?最方便的途径自然是互联网,所以就有很多人写的爬虫 没日没夜的在互联网上”横行“,有些速度太快的爬虫甚至会让网站不堪重负,甚至宕机!

为了应对这种困扰,很多网站的运营者就想出了很多 反爬虫 的技术
这大概分为四个种类:

一、通过User-Agent来控制访问:

无论是浏览器还是爬虫程序,在向服务器发起网络请求的时候,都会发过去一个头文件:headers,比如知乎的requests headers:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,da;q=0.2,la;q=0.2
Cache-Control:max-age=0
Connection:keep-alive
Cookie: **********
Host:zhuanlan.zhihu.com
Referer:Ehco - 知乎
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Query String Parameters
view source
view URL encoded

这里面的大多的数的字段都是浏览器向服务器”表明身份“用的
对于爬虫程序来说,我们最需要注意的字段就是:”User-Agent:“
很多网站都会建立 user-agent白名单,只有属于正常范围的user-agent才能够正常访问。

比如知乎:

import requests
import bs4
import random


def get_html(url):
    try:
        r = requests.get(url, timeout=30)
        r.raise_for_status
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return "Someting Wrong!"
        
print(get_html('https://zhuanlan.zhihu.com'))

# OUT:
'''
<html><body><h1>500 Server Error</h1>
An internal server error occured.
</body></html>
'''

可以看到,我们的请求被拒绝了,并且返回了一个500的错误码:
这里就是因为我们requests库本身的headers是这样的:

{'Date': 'Tue, 09 May 2017 12:13:00 GMT', 'Content-Type': 'text/html', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Set-Cookie': 'aliyungf_tc=AQAAAPDDXQnf6AEAHaBXcP1tHo5z1uta; Path=/; HttpOnly, acw_tc=AQAAAAM
89GeptQMAHaBXcJiyTK3l8c5g; Path=/; HttpOnly', 'Cache-Control': 'no-cache'}

这里面并没有user-agent字段,自然不被知乎的服务器所接受了。

如何去解决呢?

我们可以自己设置一下user-agent,或者更好的是,我们从一系列的user-agent里随机挑出一个符合标准的使用,代码如下:

def get_agent():
    '''
    模拟header的user-agent字段,
    返回一个随机的user-agent字典类型的键值对
    '''
    agents = ['Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;',
              'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv,2.0.1) Gecko/20100101 Firefox/4.0.1',
              'Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11',
              'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
              'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)']
    fakeheader = {}
    fakeheader['User-agent'] = agents[random.randint(0, len(agents))]
    return fakeheader
    
    # 注意看新的请求函数:
    
    def get_html(url):
    try:
        r = requests.get(url, timeout=30,headers=get_agent())
        r.raise_for_status
        r.encoding = r.apparent_encoding
        return r.status_code    
    except:
        return "Someting Wrong!"
       
    '''
    OUT:
    200
    ''' 
    

二、通过IP限制来反爬虫:

就和悦音台程序里说的一样,如果一个固定的ip在短暂的时间呢,快速大量的访问一个网站,那自然会引起注意,管理员可以通过一些手段把你这个不听话的ip给封了,你的爬虫自然也就做不了什么了。

如何解决?

比较成熟的方式是:IP代理池
简单的说,就是通过ip代理,从不同的ip进行访问,这样就不会被封掉ip了。
可是ip代理的获取本身就是一个很麻烦的事情,网上有免费和付费的,但是质量都层次不齐。如果是企业里需要的话,可以通过自己购买集群云服务来自建代理池。

我这里实现了一个简单的代理转换,分享给大家:

def get_proxy():
    '''
    简答模拟代理池
    返回一个字典类型的键值对,
    '''
    proxy = ["http://116.211.143.11:80",
             "http://183.1.86.235:8118",
             "http://183.32.88.244:808",
             "http://121.40.42.35:9999",
             "http://222.94.148.210:808"]
    fakepxs = {}
    fakepxs['http'] = proxy[random.randint(0, len(proxy))]
    
    return fakepxs

三、通过JS脚本来防止爬虫:

这个可以说是终极的办法了,因为,爬虫终归只是一段程序,他并不能像人一样去应对各种变化,如验证码,滑动解锁之类的。
举个例子:我曾经想爬一个分享百度云电影的网站,但是在进入网站之前,他会有一个验证页面来验证你是不是机器。
他是怎么验证的呢:

他会通过js代码生成一大段随机的数字,然后要求浏览器通过js的运算得出这一串数字的和,再返回给服务器.

可想而知的是,这么简单和最基础的一个验证步骤,我们从前写的代码是完成不了的。

如何解决呢?
这里就要请出我们的大杀器:”PhantomJS“

PhantomJS是一个Python包,他可以在没有图形界面的情况下,完全模拟一个”浏览器“,对你没看错,就是浏览器,这样的话,js脚本验证什么的再也不是问题了。

关于PhantomJS是如何使用的,我会在后续的文章进行说明和记录。

四、通过robots.txt来限制爬虫:

说起来,世界上做爬虫最大最好的就是Google了,搜索引擎本身就是一个超级大的爬虫,Google开发出来爬虫24h不间断的在网上爬取着新的信息,并返回给数据库,但是这些搜索引擎的爬虫都遵守着一个协议:robots.txt

robots.txt(统一小写)是一种存放于网站根目录下的ASCII编码的文本文件,它通常告诉网络搜索引擎的漫游器(又称网络蜘蛛),此网站中的哪些内容是不应被搜索引擎的漫游器获取的,哪些是可以被漫游器获取的。因为一些系统中的URL是大小写敏感的,所以robots.txt的文件名应统一为小写。robots.txt应放置于网站的根目录下。如果想单独定义搜索引擎的漫游器访问子目录时的行为,那么可以将自定的设置合并到根目录下的robots.txt,或者使用robots元数据(Metadata,又称元数据)。
robots.txt协议并不是一个规范,而只是约定俗成的,所以并不能保证网站的隐私。注意robots.txt是用字符串比较来确定是否获取URL,所以目录末尾有与没有斜杠“/”表示的是不同的URL。robots.txt允许使用类似"Disallow: *.gif"这样的通配符[1][2]。

wiki上说的已经很清楚了,这实际上只是一个”君子协议“,遵守与否,都在于爬虫的编写者。

我们来看一下京东的'robots.txt':

User-agent: * 
Disallow: /?* 
Disallow: /pop/*.html 
Disallow: /pinpai/*.html?* 
User-agent: EtaoSpider 
Disallow: / 
User-agent: HuihuiSpider 
Disallow: / 
User-agent: GwdangSpider 
Disallow: / 
User-agent: WochachaSpider 
Disallow: /

可以看到,jd的robots协议里明确的支出四个”user-agent”是禁止访问的,
事实上,这四个user-agent也是四个臭名昭著的恶性爬虫,有兴趣的同学可以去自己搜索一下这些爬虫都是怎样的!

我在这里呼吁大家 遵守这个规则!,互联网上的很多资源都是免费的,但是如果因为个人的利益,而损害到别人,这是很不对的!

当然有种情况是例外的,比如说我们爬虫的获取网页的速度,和人类浏览网页是差不多的,这并不会给服务器造成太大的性能损失,在这种情况下,我们是可以不用恪守 robots协议的。


好了到这里,我们requests--bs4 线路的爬虫学习就要告一段落了,相信到这里大家对于爬虫都有了自己更深的理解了吧?bs4库是一个非常强大的第三方爬虫库,用好他对于我们的生活学习都有很大的帮助!从下一次开始,我们就要开始学习Scrapy框架了!这是一个十分厉害的库,能够成体系的编写一些上规模的爬虫,很多商业公司都在用这个框架来爬取数据哦!


每天的学习记录都会 同步更新到:
微信公众号: findyourownway

知乎专栏:从零开始写Python爬虫 - 知乎专栏

blog : www.ehcoblog.ml

Github: Ehco1996/Python-crawler

发布于 2017-05-09

文章被以下专栏收录