Python小白使用爬虫提取豆瓣电视剧数据

我…我…我是看着好久没更新Python的文章了,于是我将魔爪伸向了Python来水一文

准备工作

在开始干爬虫之前你肯定要安装Python的环境,也就是Python语言的解释器,还有Python的编辑器,Pycharm。这些之前都有说过,可以参考之前的分类文章

为了能够敏捷而又不失优雅地完成这次操作,我慎(tou)重(lan)选择了直接进行实战演练,废话不多说,开干

分析豆瓣URL

写爬虫之前肯定是要分析链接的,不然你怎么去爬,而且爬取数据我们尽量去找一些返回json数据的URL,因为json更好处理数据,但是并不是所有的站点返回数据都是json

怎么找返回json的URL呢?

  1. 打开浏览器的抓包工具,查看网络请求,当然你也可以使用FD等这些专业的工具
  2. 把浏览器网页切换到手机版

国产剧 – 电视 – 豆瓣的URL:https://m.douban.com/tv/chinese

然后我们按下F12打开浏览器的抓包工具,查看network这一栏就可以看到有一条这样的请求

items?os=ios&for_mobile=1&callback=jsonp1&start=0&count=18&loc_id=108288&_=1527155131544

点击它,看它的Request URL:

https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_domestic_hot/items?os=ios&for_mobile=1&callback=jsonp1&start=0&count=18&loc_id=108288&_=1527155131544

我们会发现我们访问的URL跟他请求是URL不同,然后我们查看它的Response就会看到一些json数据

浏览器的抓包工具
浏览器的抓包工具

美剧 – 电视 – 豆瓣的URL:https://m.douban.com/tv/american

美剧的Request URL:

https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_american_hot/items?os=ios&for_mobile=1&callback=jsonp1&start=0&count=18&loc_id=108288&_=1527154794289

分析一下这两个URL

/filter_tv_domestic_hot/是根据这个参数来判断电视剧的类型,strat的值也会变,这个表示我们已经获取的数量

请求这个URL能够返回一个json字符串,我们能够将它转换为一个Python字典,就能够从中提取数据了,但是我们发现这个请求返回的数据中有一个jsonp1,这个jsonp1中间包括的才是一个字典,而外面这个jsonp1并不是我们所需要的数据

数据带有jsonp1
数据带有jsonp1

无论在爬其他网站的时候还是爬豆瓣的时候,如果发现返回的数据包含这个jsonp1、jsonp2…99在前面的时候,说明它的URL参数包含callback=jsonp1,要解决这个问题的话,我们就将这个参数删除掉,就可以将响应变成一个非常完美的json字符串

处理后得到的json数据
处理后得到的json数据

构建代码

骚气的分析了这么多,下面开始代码,新建一个py文件

定义一个run方法,主要实现我们的逻辑,先写一下我们的思路

def run():
    #1.url_list 带请求的是临时地址
    #2.发送请求 获取响应
    #3.提取数据
    #4.保存

然后进行异常处理+请求数据

from retrying import retry

@retry(stop_max_attempt_number=3)
def _parse_url(url):
    print("*"*100)
    r = requests.get(url,headers=headers,timeout=5) #可能会超时报错
    assert r.status_code == 200 #可能会请求不成功报错
    return r.content.decode()

def parse_url(url):
    try:
        html = _parse_url(url)
    except Exception as e:
        print("报错了:",e)
        html = None
    return html

完整的代码如下

import json
import requests
from retrying import retry

headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
           "Referer":"https://m.douban.com/tv/american"}#referer 豆瓣新加的

@retry(stop_max_attempt_number=3)
def _parse_url(url):
    print("*"*100)
    r = requests.get(url,headers=headers,timeout=5) #可能会超时报错
    assert r.status_code == 200 #可能会请求不成功报错
    return r.content.decode()

def parse_url(url):
    try:
        html = _parse_url(url)
    except Exception as e:
        print("报错了:",e)
        html = None
    return html

def get_url_list():#1.url_list 带请求的是临时地址
    url_list = [
        {
            "url_temp":"https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_american_hot/items?os=ios&for_mobile=1&start={}&count=18",
            "country":"UK"
        },
        {
            "url_temp":"https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_english_hot/items?os=ios&for_mobile=1&start={}&count=18",
            "country": "US"
        },
       {
           "url_temp": "https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_domestic_hot/items?os=ios&for_mobile=1&start={}&count=18",
           "country": "China"
       }
    ]
    return url_list

def get_content_list(json_response):
    dict_response = json.loads(json_response)
    content_list = dict_response["subject_collection_items"]
    total_num = dict_response["total"]
    return  content_list,total_num

def save_content_list(content_list):
    for content in content_list:
        print(content)
        print("*"*100)


def run():
    #1.url_list 带请求的是临时地址
    url_list_temp = get_url_list()
    for temp in url_list_temp:
        num = 0
        total_num = 100
        while num<=total_num+18:
            url = temp["url_temp"].format(str(num))
            #2.发送请求 获取响应
            json_response = parse_url(url)
            #3.提取数据
            content_list,total_num = get_content_list(json_response)
            #4.保存
            for content in content_list: #添加国家信息
                content["country"] = temp["country"]
            save_content_list(content_list)
            num += 18



if __name__ == '__main__':
    run()

反爬虫一些问题

有时候可能爬取不出来数据,这就说明豆瓣进行了升级或者你的爬虫被封禁了

单个ip单个用户在短时间内请求网站数据过快,都会被豆瓣的反爬虫机制发现并判断为机器操作而封禁,解决的方法有几种

1.使用ip代理池,隔一段时间随机换一个ip

2.降低爬取速度,设置爬虫间隔时间

3.将爬取内容分块,分时间段爬取

4 条评论

发表评论

*