项目一:爬取猫眼电影榜单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节点内的信息,正则表达式写为:

.*?board-index.*?>(.*?)

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

.*?board-index.*?>(.*?).*?data-src="(.*?)"

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

.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?)

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

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

.*?board-index.*?>(.*?).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star.*?>(.*?)

.*?releasetime.*?>(.*?)

.*?integer.*?>(.*?).*?fraction.*?>(.*?).*?

我们使用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'
.*?board-index.*?(\d+).*?(.*?).*?"star">(.*?)

.*?"releasetime">(.*?)

*?"interger">(.*?).*?"faraction">(.*?)', re.S) pattern = re.compile(r'
.*?board-index.*?>(\d+).*?data-src="(.*?)".*?name">(.*?).*?star">(.*?)

.*?releasetime">(.*?)

.*?integer">(.*?).*?fraction">(.*?).*?
', 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'
.*?board-index.*?(\d+).*?(.*?).*?"star">(.*?)

.*?"releasetime">(.*?)

*?"interger">(.*?).*?"faraction">(.*?)', re.S) pattern = re.compile(r'
.*?board-index.*?>(\d+).*?data-src="(.*?)".*?name">(.*?).*?star">(.*?)

.*?releasetime">(.*?)

.*?integer">(.*?).*?fraction">(.*?).*?
', 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网络爬虫开发实践》,作者崔庆才

你可能感兴趣的:(项目一:爬取猫眼电影榜单Top100)