项目一:爬取猫眼电影榜单Top100

一、项目描述

本项目是利用requests库和正则表达式来抓取猫眼电影榜单TOP100的相关内容。至于解析工具,在不使用xpath、bs4以及pyquery等解析工具的情况下,正则表达式无疑是最直接、最暴力的提取页面的方法。

二、准备工作

安装好requests库,若未安装,使用如下命令进行安装:

pip install requests

三、爬取分析

1)爬取网页的url
url = "https://maoyan.com/board/4"
如图所示:

图1 爬取的网页

2)翻页问题
将网页翻到最底部,发现有分页,点击下一页:

图2 分页问题

此时分析,第一页的时候,url没有出现offset,第2页的offset(偏移量)是10,第3页:offset=20......

以此类推,可得:

第一页:offset 无
第二页:offset = 10
第三页:offset = 20
第四页:offset = 30
...
第十页:offset = 90

四、爬取解析页面

1)爬取一个页面
首先抓取一个页面的内容。我们实现了get_page()方法,并给它传入url参数。然后将抓取的页面结果返回,再通过main()方法调用。初步代码实现如下:

# 创建发起请求
# 返回网页文本
def get_page(url):
    try:
        # 请求头
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
        }

        # 创建请求
        req = urllib.request.Request(url=url, headers=headers)

        # 发起请求,得到相应
        res = urllib.request.urlopen(req)

        if res.getcode() == 200:
            # 返回页面文本
            return res.read().decode("utf-8")
        return None
    except BaseException as e:
        return None

2)提取页面
这里面我们将上面获取的页面用正则提取出来,注意,这里不要在Elements选项卡中直接查看源码,因为那里的源码可能经过JavaScript操作而与原始请求不同,而是需要从Network选项卡部分查看原始请求得到的源码。

查看其中一个条目的源代码,如图3所示。

图3 网页源码分析

可以看到,一部电影信息对应的源代码是一个dd节点,我们用正则表达式来提取这里面的一些电影信息。

首先,需要提取它的排名信息。而它的排名信息是在class为board-index的i节点内,这里利用非贪婪匹配来提取i节点内的信息,正则表达式写为:

<dd>.*?board-index.*?>(.*?)</i>

随后需要提取电影的图片。可以看到,后面有a节点,其内部有两个img节点。经过检查后发现,第二个img节点的data-src属性是图片的链接。这里提取第二个img节点的data-src属性,正则表达式可以改写如下:

<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)"

再往后,需要提取电影的名称,它在后面的p节点内,class为name。所以,可以用name做一个标志位,然后进一步提取到其内a节点的正文内容,此时正则表达式改写如下:

<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>

【其他电影信息的正则,不一一赘述】

最终写出来的正则表达式如下【每个人写正则表达式略有不同】:

<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>

我们使用findll()函数来匹配正则,返回一个列表,效果如下:

[('1','http://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c', '霸王别姬', '\n 主演:张国荣,张丰毅,巩俐\n ', '上映时间:1993-01-01(中国香港)', '9.', '6'),
('2','http://p0.meituan.net/movie/__40191813__4767047.jpg@160w_220h_1e_1c', '肖申克的救赎', '\n 主演:蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿\n ', '上映时间:1994-10-14(美国)', '9.', '5'),
('3','http://p0.meituan.net/movie/fc9d78dd2ce84d20e53b6d1ae2eea4fb1515304.jpg@160w_220h_1e_1c', '这个杀手不太冷', '\n 主演:让·雷诺,加里·奥德曼,娜塔莉·波特曼\n ', '上映时间:1994-09-14(法国)', '9.', '5'),
('4','http://p0.meituan.net/movie/23/6009725.jpg@160w_220h_1e_1c', '罗马假日', '\n 主演:格利高利·派克,奥黛丽·赫本,埃迪·艾伯特\n ', '上映时间:1953-09-02(美国)', '9.', '1'),
('5','http://p0.meituan.net/movie/53/1541925.jpg@160w_220h_1e_1c', '阿甘正传', '\n 主演:汤姆·汉克斯,罗宾·怀特,加里·西尼斯\n ', '上映时间:1994-07-06(美国)', '9.', '4'),
('6','http://p0.meituan.net/movie/11/324629.jpg@160w_220h_1e_1c', '泰坦尼克号', '\n 主演:莱昂纳多·迪卡普里奥,凯特·温丝莱特,比利·赞恩\n ', '上映时间:1998-04-03', '9.', '5'),
('7','http://p0.meituan.net/movie/99/678407.jpg@160w_220h_1e_1c', '龙猫', '\n 主演:日高法子,坂本千夏,糸井重里\n ', '上映时间:1988-04-16(日本)', '9.', '2'),
('8','http://p0.meituan.net/movie/92/8212889.jpg@160w_220h_1e_1c', '教父', '\n 主演:马龙·白兰度,阿尔·帕西诺,詹姆斯·凯恩\n ', '上映时间:1972-03-24(美国)', '9.', '3'),
('9','http://p0.meituan.net/movie/62/109878.jpg@160w_220h_1e_1c', '唐伯虎点秋香', '\n 主演:周星驰,巩俐,郑佩佩\n ', '上映时间:1993-07-01(中国香港)', '9.', '2'),
('10','http://p0.meituan.net/movie/9bf7d7b81001a9cf8adbac5a7cf7d766132425.jpg@160w_220h_1e_1c', '千与千寻', '\n 主演:柊瑠美,入野自由,夏木真理\n ', '上映时间:2001-07-20(日本)', '9.', '3')]

很明显,每一条数据,都是存放在一个元组里面,所以我们应该把它们取出来,利用字典将对应的数据存储下来。

最后使用生成器(一个容器),将一个页面的10部电影信息,也就是10条数据存储在其中,代码实现如下:

# 解析页面 正则
def parge_page(html_text):
    # pattern = re.compile(r'<dd>.*?board-index.*?(\d+)</li>.*?<img data_src="(.*?)".*?="name"><a.*?>(.*?)</a>.*?"star">(.*?)</p>.*?"releasetime">(.*?)</p>*?"interger">(.*?)</i>.*?"faraction">(.*?)</i>', re.S)
    pattern = re.compile(r'<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S)


    # 匹配
    items = re.findall(pattern, html_text)
    print(items)
    # print()

    for item in items:
        dic = { 
            'index': item[0],
            'image': item[1],
            'title': item[2],
            'actor': item[3].strip()[3:],
            'time': item[4].strip()[5:],
            'score': item[5] + item[6]
            }
        yield dic

五、写入文件

写入文件就简单的多了,我直接上代码:

# 写入文件
def write_to_file(item):
    with open('./猫眼电影Top100.txt', 'a', encoding='utf-8') as fp:
        fp.write(json.dumps(item, ensure_ascii=False) + '\n\n')

六、main():对外的接口函数

利用main()函数来作为对外的接口函数,调用get_page()、parse_page()函数。
代码如下:

# 主函数
def main(offset):
    # 请求url
    url = "https://maoyan.com/board/4?offset={}".format(offset)
    print("请求url:" + url)

    # 创建发起请求
    html_text = get_page(url)
    # print(html_text)

    # 解析文本
    # 得到的items是一个列表
    # 列表里面有十条数据
    # 每一页就是items
    # 然后将每一页的10条数据存入生成器
    # 然后这个生成器作为返回值传给外面的变量

    items = parge_page(html_text)
    print(type(items))

    # 写入文件
    for item in items:
        # print("itme: " + item)
        write_to_file(item)

七、爬取所有页面电影信息

利用if __name__ == '__main__'函数, 将main函数的参数offset传过去,代码如下:
【ps:关于if __name__ == '__main__'函数的理解,请参考我的另外一篇简书:https://www.jianshu.com/p/8f696f15e219

if __name__ == '__main__':
    for i in range(10):
        main(i*10)
        time.sleep(1)

八、总结

爬取猫眼电影榜单-->Top100代码如下:

#!C:/SoftWare/Virtualenv/python3
# @FileName: 06-猫眼电影排行
# @Author: 李易阳
# @Time: 2019/2/27
# @Soft: PyCharm

# 任务:爬取猫眼电影榜单下top100

# 导包
import re
import json
import time
import urllib.request

# 创建发起请求
# 返回网页文本
def get_page(url):
    try:
        # 请求头
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
        }

        # 创建请求
        req = urllib.request.Request(url=url, headers=headers)

        # 发起请求,得到相应
        res = urllib.request.urlopen(req)

        if res.getcode() == 200:
            # 返回页面文本
            return res.read().decode("utf-8")
        return None
    except BaseException as e:
        return None


# 解析页面 正则
def parge_page(html_text):
    # pattern = re.compile(r'<dd>.*?board-index.*?(\d+)</li>.*?<img data_src="(.*?)".*?="name"><a.*?>(.*?)</a>.*?"star">(.*?)</p>.*?"releasetime">(.*?)</p>*?"interger">(.*?)</i>.*?"faraction">(.*?)</i>', re.S)
    pattern = re.compile(r'<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S)


    # 匹配
    items = re.findall(pattern, html_text)
    print(items)
    # print()

    for item in items:
        yield {
            'index': item[0],
            'image': item[1],
            'title': item[2],
            'actor': item[3].strip()[3:],
            'time': item[4].strip()[5:],
            'score': item[5] + item[6]
        }


# 写入文件
def write_to_file(item):
    with open('./猫眼电影Top100.txt', 'a', encoding='utf-8') as fp:
        fp.write(json.dumps(item, ensure_ascii=False) + '\n\n')


# 主函数
def main(offset):
    # 请求url
    url = "https://maoyan.com/board/4?offset={}".format(offset)
    print("请求url:" + url)

    # 创建发起请求
    html_text = get_page(url)
    # print(html_text)

    # 解析文本
    # 得到的items是一个列表
    # 列表里面有十条数据
    # 每一页就是items
    # 然后将每一页的10条数据存入生成器
    # 然后这个生成器作为返回值传给外面的变量

    items = parge_page(html_text)
    print(type(items))

    # 写入文件
    for item in items:
        # print("itme: " + item)
        write_to_file(item)


if __name__ == '__main__':
    for i in range(10):
        main(i*10)
        time.sleep(1)
@墨雨出品 必属精品 如有雷同 纯属巧合
`非学无以广才,非志无以成学!`

参考资料《Python3网络爬虫开发实践》,作者崔庆才

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