爬虫demo——爬取电影天堂的资源,存储到本地json文件

电影天堂里面的数据还是非常丰富的,这次的爬虫demo,是对电影天堂中的电影数据进行爬取,包括电影片名,导演,主演,演员等信息以及最后的迅雷下载地址。
经过4000部电影的爬取测试,我对代码多次进行优化,目前为止已没有什么bug,至少可以顺利对网站中的电影进行爬取。

一、基本介绍

文章的最后,我会给出爬虫的完成代码,文章中的代码片段如果看上去比较乱的话,可以在了解爬虫步骤和思想之后,通过完成代码来梳理自己的思路。

本次爬虫使用到三个库,用于请求网页内容的requests库,用于对网页内容数据进行过滤处理的lxml库,已经用于json格式转换的json

所以在使用之前要引入这些库,并且保证自己项目中包含这些库,如果没有,自行进行安装。

import requests
from lxml import etree
import json

二、分析电影的链接,为爬虫做准备

首先对电影天堂进行分析,我注意到网站首页有【2018新片精品】这一个版块,点击右边的更多按钮,可以来到电影的列表页。

通过对点一个列表页的分析,我发现这不仅仅是2018的最新电影,一共有179页,共4473条数据。仔细分析之后,发现最早的影片是2009年的。所以当时就决定对和4000多部电影进行爬取。

分析这些列表的URL,不难发现其中的规律,列表的URL如下:

其中首页比较特殊,我们第一次点进行,看到的URL是http://www.dytt8.net/html/gndy/dyzz/index.html,但是我们从其他页面跳转到首页,会发现地址为http://www.dytt8.net/html/gndy/dyzz/list_23_1.html,完全符合上面的规律。

于是我写了下面代码,一次性生成全部的电影列表页(第1页~第179页)的URL,并存储到列表中:

def movie_list_page():
    base_url = "http://www.dytt8.net/html/gndy/dyzz/list_23_{}.html"
    page_urls = []
    for x in range(1, 180):
        page_urls.append(base_url.format(x))

    return page_urls

现在我们只是获取到电影的列表页地址,下一步我们是要从这些列表页中,获取每一步电影的详情页面地址,比如对于《人类清除计划》这部电影,我们需要获取这个地址:http://www.dytt8.net/html/gndy/dyzz/20180919/57492.html

明确这一点,下面我们要开始爬取列表页中的内容。这一步是非常简单的,简单看一下页面就会知道,这些电影的详情页地址肯定是很规律的。大多数是ul标签下的li标签或者是table标签,于是我写了下面这些代码,获取电影的详情页地址:

# 传入电影列表页地址,返回这一页中每一部电影的详情页面链接
def get_detail_url(url):
    BASE_DIMAIN = "http://www.dytt8.net"  # 定义基础域名
    response = requests.get(url, headers=HEADERS)
    text = response.text
    html = etree.HTML(text)
    detail_urls = html.xpath("//table[@class='tbspan']//a[@href!='/html/gndy/jddy/index.html']/@href")
    detail_urls = map(lambda x: BASE_DIMAIN + x, detail_urls)

    return detail_urls

三、请求电影的详情页面,过滤数据

现在我们拿到了所有的电影列表页地址,即从第1页到第179页的地址。在代码中使用循环语句,通过这些地址我们又能够获取每一页中所有电影的详情页面信息。这样一来我们就相当于成功一半,下面的工作就是请求电影详情页面中的数据,以及对这些数据进行过滤和处理。

首先我们使用requests库,将电影详情页面中的所有内容全部请求下来,然后获取存放电影信息的那块内容,缩小我们的数据范围,方便我们进一步过滤数据。代码如下:

movie = {}        # 用作后面的存放电影的数据
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
}
detail_response = requests.get(url, headers=HEADERS)
detail_text = detail_response.content.decode(encoding="gb18030", errors="ignore")    # 注意这里设置的编码格式是根据电影天堂的编码格式来的,同时设置errors="ignore",忽略一些极其特殊的字符的解码错误
detail_html = etree.HTML(detail_text)
if len(detail_html.xpath("//div[@id='Zoom']")) > 0:
    zoom = detail_html.xpath("//div[@id='Zoom']")[0]
else:
    return movie            # 说明没有爬取成功,直接跳过返回一个空字典,放弃对这一步电影的爬取

由于电影天堂中,关于电影内容的部分的数据表示不够明显,比如没有特定的class和id来标识。所有我们需要通过xpath语法中的text()获取表示电影内容的文本信息列表,然后对这些列表进行遍历,过滤我们需要的信息,具体代码如下:

movie = {}        # 用作后面的存放电影的数据
# text_list = zoom.xpath(".//p/text()|.//p/span/text()")        # 版本1.0,没有考虑到有的页面中会多出span标签
# text_list = zoom.xpath(".//p/span/text()|.//p/text()")        # 版本2.0,没有考虑到有的页面中会缺少标签
text_list = zoom.xpath(".//text()")                             # 版本3.0,直接获取页面中的文本,进行过滤
for (index, text) in enumerate(text_list):
    # print(text)
    if text.startswith("◎译  名"):
        movie["teanslation_title"] = text.replace("◎译  名", "").strip()
    elif text.startswith("◎片  名"):
        movie["real_title"] = text.replace("◎片  名", "").strip()
    elif text.startswith("◎年  代"):
        movie["time"] = text.replace("◎年  代", "").strip()
    elif text.startswith("◎产  地"):
        movie["place"] = text.replace("◎产  地", "").strip()
    elif text.startswith("◎类  别"):
        movie["category"] = text.replace("◎类  别", "").strip()
    elif text.startswith("◎语  言"):
        movie["language"] = text.replace("◎语  言", "").strip()
    elif text.startswith("◎上映日期"):
        movie["release_time"] = text.replace("◎上映日期", "").strip()
    elif text.startswith("◎豆瓣评分"):
        movie["douban_score"] = text.replace("◎豆瓣评分", "").strip()
    elif text.startswith("◎片  长"):
        movie["length"] = text.replace("◎片  长", "").strip()
    elif text.startswith("◎导  演"):
        movie["director"] = text.replace("◎导  演", "").strip()
    elif text.startswith("◎主  演"):
        actors = []
        actors.append(text.replace("◎主  演", "").strip())
        for num in range(index + 1, index + 10):
            if (text_list[num].startswith("◎简  介")):
                break
            else:
                actors.append(text_list[num].strip())
        movie["actors"] = actors
    elif text.startswith("◎简  介"):
        conttent_index = index + 1
        movie["introduction"] = text_list[conttent_index].strip()

# 由于页面的原因,对下载链接进行特殊过滤
if len(zoom.xpath(".//td/a/@href")) > 0:
    download_url = zoom.xpath(".//td/a/@href")[0]
elif len( zoom.xpath(".//td//a/@href")) > 0 :
    download_url = zoom.xpath(".//td//a/@href")[-1]
else:
    download_url = "爬取失败,手动修改迅雷下载链接!"

movie["download_url"] = download_url
print("·", end=" ")             # 简单的标识,在爬取的时候,成功爬取一部电影,就会打印出一个“·”
return movie

四、将数据处理成json格式,保存到本地json文件中

完成上述任务,我们的爬虫也基本上已经接近尾声。下面要做的就是,调用封装上述代码的函数,将数据处理成json格式,然后以每一列表为单位,存储到本地json文件中。

page_num = 1
page_urls = movie_list_page()
# 以每一列表页为单位,完成每一列表页中电影的爬取,处理成json,写入到本地文件中
for (index, page_url) in enumerate(page_urls):
    file_name = "new_movie_" + str(index + page_num) + ".json"      # 设置存放每一页电影信息的json文件的名称
    one_page_movie_content = []     # 每一页中所有电影的信息
    movie_detail_urls = get_detail_url(page_url)
    for movie_detail_url in movie_detail_urls:
        movie_content = get_movie_content(movie_detail_url)
        one_page_movie_content.append(movie_content)
    # 将爬取的每一页的电影数据,分别写入到一个json文件中
    one_page_movie_content_str = json.dumps(one_page_movie_content, ensure_ascii=False, indent=2)
    with open(file_name, "w", encoding="utf-8") as f:
        f.write(one_page_movie_content_str)
    print("第" + str(index + page_num) + "页电影爬取完成,写入到" + file_name + "文件中")

四、爬虫完成代码下载:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容