抓取猫眼TOP100电影信息

作者: 编程新视野 | 来源:发表于2019-01-25 14:56 被阅读0次

    本文介绍利用Requests库、multiprocessing库和正则表达式爬取猫眼电影TOP100电影的相关信息,提取出电影名称、上映时间、评分、封面图片等信息,将爬取的内容写入到文件中。站点URL为 http://maoyan.com/board/4

    注释:源码视频书籍练习题等资料进群696541369 即可免费获取

    准备

    本文使用了Requests库,使用pip安装: pip install requests

    分析

    打开http://maoyan.com/board/4,可以看到榜单信息。如下图所示

    排名第一的电影是霸王别姬,可以提取的信息有电影名称、主演、上映时间、评分、封面图等。

    点击页面下方的分页列表翻页到第二页,会发现URL会变成,比首页多了个offset=10 参数,而目前显示的是排名11-20的电影,初步判断这是偏移量参数。再点击下一页,URL变成了

    https://maoyan.com/board/4?offset=20

    offset变成了20,显示的是排名21-30的电影。

    由此可见,offset代表偏移量,偏移量为n,则显示的是排名n+1~n+10的电影,每页显示10个电影。所以,想要获取TOP100电影信息,只要分开获取10次,只需把10次请求的URL中offset参数分别设为 0,10,20,30...90即可(首页的offset值为0)。获取到不同的网页后使用正则表达式提取出我们要的信息,就可以得到TOP100电影信息了,可以使用多线程加速爬取。

    爬取实现

    爬取首页

    实现get_page()方法,传入url参数可以将抓取的页面结果返回。以下代码获取首页内容:

    import requests

    from requests.exceptions import RequestException

    def get_page(url):

    headers = {

    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'

    }

    response = requests.get(url,headers = headers)

    try:

    if response.status_code == 200:

    return response.text

    return None

    except RequestException:

    print("request error")

    return None

    def main():

    html = get_page('https://maoyan.com/board/4')

    print(html)

    main()

    运行之后就成功获取到了首页的源代码,接下来使用正则表达式进行解析,提取出我们想要的信息。

    正则提取

    回到浏览器页面,在开发者工具Network监听组件中查看源代码。如图:

    值得注意的是这里不是从Elements选项卡里查看的源代码,因为Elements里看到的源代码很有可能经过Javascript处理过从而和原始请求不同,所以要从Network选项卡里查看原始请求得到的源码。

    查看此处代码:

    不难发现,要爬取的每部电影信息都在<dd>标签里,接下来使用正则表达式提取信息。

    首先,提取它的排名信息,它的排名信息在class为board-index的i标签里,使用非贪婪匹配来提取i内的信息,正则表达式可以写为:<dd>.*?board-index.*?>(d+)</i>

    接下来提取电影的封面图片。在排名后面的a便签里有两个img便签,经过检查,第二个img是电影的封面图片,正则:.*?data-src="(.*?)"

    然后提取电影的名称,它在class为name的<p>便签内,可以使用name作为标志位进一步提取到其内a的文本内容,正则写为:.*?name.*?a.*?>(.*?)</a>

    提取主演:.*?star">(.*?)</p>

    提取上映时间:.*?releasetime">(.*?)</p>

    提取评分:.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>

    最后正则表达式写为:

    .*?board-index.*?>(d+).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star">(.*?).*?releasetime">(.*?).*?integer">(.*?).*?fraction">(.*?).*?

    上面的正则表达式可以匹配一个电影,匹配了7条信息,接下来可以通过findall()方法提取所有内容。可以定义一个用来解析页面的方法parse_page(),代码如下:

    def parse_page(html):

    pattern = re.compile('.*?board-index.*?>(d+).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star">(.*?)'

    + '.*?releasetime">(.*?).*?integer">(.*?).*?fraction">(.*?).*?',r.S) #re.S使.能匹配任意字符

    items = pattern.findall(str(html))

    这样就成功得拿到了一页10个电影的信息,这是一个列表,获取到的结果如下:

    [('1', 'https://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c', '霸王别姬', ' 主演:张国荣,张丰毅,巩俐 ', '上映时间:1993-01-01', '9.', '6'), ('2', 'https://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c', '肖申克的救赎', ' 主演:蒂姆·罗宾斯,摩

    根·弗里曼,鲍勃·冈顿 ', '上映时间:1994-10-14(美国)', '9.', '5'), ('3', 'https://p0.meituan.net/movie/54617769d96807e4d81804284ffe2a27239007.jpg@160w_220h_1e_1c', '罗

    马假日', ' 主演:格利高里·派克,奥黛丽·赫本,埃迪·艾伯特 ', '上映时间:1953-09-02(美国)', '9.', '1'), ('4', 'https://p0.meituan.net/movie/e55ec5d18ccc

    83ba7db68caae54f165f95924.jpg@160w_220h_1e_1c', '这个杀手不太冷', ' 主演:让·雷诺,加里·奥德曼,娜塔莉·波特曼 ', '上映时间:1994-09-14(法国)', '9.', '

    5'), ('5', 'https://p1.meituan.net/movie/f5a924f362f050881f2b8f82e852747c118515.jpg@160w_220h_1e_1c', '教父', ' 主演:马龙·白兰度,阿尔·帕西诺,詹姆斯·肯恩

    ', '上映时间:1972-03-24(美国)', '9.', '3'), ('6', 'https://p1.meituan.net/movie/0699ac97c82cf01638aa5023562d6134351277.jpg@160w_220h_1e_1c', '泰坦尼克号', '

    主演:莱昂纳多·迪卡普里奥,凯特·温丝莱特,比利·赞恩 ', '上映时间:1998-04-03', '9.', '5'), ('7', 'https://p0.meituan.net/movie/da64660f82b98cdc1b8a3804e69609e04110

    8.jpg@160w_220h_1e_1c', '唐伯虎点秋香', ' 主演:周星驰,巩俐,郑佩佩 ', '上映时间:1993-07-01(中国香港)', '9.', '2'), ('8', 'https://p0.meituan.net/movie/b076ce63e9860ecf1ee9839badee5228329384.jpg@160w_220h_1e_1c', '千与千寻', ' 主演:柊瑠美,入野自由,夏木真理 ', '上映时间:2001-07-20(日本)', '9.', '3'), ('9', 'https://p0.meituan.net/movie/46c29a8b8d8424bdda7715e6fd779c66235684.jpg@160w_220h_1e_1c', '魂断蓝桥', ' 主演:费雯·丽,罗伯特·泰勒,露塞尔·沃特森

    ', '上映时间:1940-05-17(美国)', '9.', '2'), ('10', 'https://p0.meituan.net/movie/230e71d398e0c54730d58dc4bb6e4cca51662.jpg@160w_220h_1e_1c', '乱世佳人', '

    主演:费雯·丽,克拉克·盖博,奥利维娅·德哈维兰 ', '上映时间:1939-12-15(美国)', '9.', '1')]

    这样的数据看上去很杂乱,使用字典将数据格式化:

    for item in items:

    yield {

    'top':item[0],

    'image_src':item[1],

    'name':item[2],

    'actor':item[3].strip()[3:] if len(item[3]) > 3 else '',

    'releasetime':item[4].strip()[5:],

    'score':item[5] + item[6]

    }

    这样就可以获得电影信息的结构化数据了,每个电影的信息都包含在一个字典里。获得的结果如下:

    {'top': '1', 'image_src': 'https://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c', 'name': '霸王别姬', 'actor': '张国荣,张丰毅,巩俐', 'releasetime': '1993-01-01', 'score': '9.6'}

    {'top': '2', 'image_src': 'https://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c', 'name': '肖申克的救赎', 'actor': '蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿', 'releasetime': '1994-10-14(美国)', 'score': '9.5'}

    {'top': '3', 'image_src': 'https://p0.meituan.net/movie/54617769d96807e4d81804284ffe2a27239007.jpg@160w_220h_1e_1c','name': '罗马假日', 'actor': '格利高里·派克,奥黛丽·赫本,埃迪·艾伯特', 'releasetime': '1953-09-02(美国)', 'score': '9.1'}

    {'top': '4', 'image_src': 'https://p0.meituan.net/movie/e55ec5d18ccc83ba7db68caae54f165f95924.jpg@160w_220h_1e_1c', 'name': '这个杀手不太冷', 'actor': '让·雷诺,加里·奥德曼,娜塔莉·波特曼', 'releasetime': '1994-09-14(法国)', 'score': '9.5'}

    {'top': '5', 'image_src': 'https://p1.meituan.net/movie/f5a924f362f050881f2b8f82e852747c118515.jpg@160w_220h_1e_1c', 'name': '教父', 'actor': '马龙·白兰度,阿尔·帕西诺,詹姆斯·肯恩', 'releasetime': '1972-03-24(美国)', 'score': '9.3'}

    {'top': '6', 'image_src': 'https://p1.meituan.net/movie/0699ac97c82cf01638aa5023562d6134351277.jpg@160w_220h_1e_1c', 'name': '泰坦尼克号', 'actor': '莱昂纳多·迪卡普里奥,凯特·温丝莱特,比利·赞恩', 'releasetime': '1998-04-03', 'score': '9.5'}

    {'top': '7', 'image_src': 'https://p0.meituan.net/movie/da64660f82b98cdc1b8a3804e69609e041108.jpg@160w_220h_1e_1c', 'name': '唐伯虎点秋香', 'actor': '周星驰,巩俐,郑佩佩', 'releasetime': '1993-07-01(中国香港)', 'score': '9.2'}

    {'top': '8', 'image_src': 'https://p0.meituan.net/movie/b076ce63e9860ecf1ee9839badee5228329384.jpg@160w_220h_1e_1c', 'name': '千与千寻', 'actor': '柊瑠美,入野自由,夏木真理', 'releasetime': '2001-07-20(日本)', 'score': '9.3'}

    {'top': '9', 'image_src': 'https://p0.meituan.net/movie/46c29a8b8d8424bdda7715e6fd779c66235684.jpg@160w_220h_1e_1c', 'name': '魂断蓝桥', 'actor': '费雯·丽,罗伯特·泰勒,露塞尔·沃特森', 'releasetime': '1940-05-17(美国)', 'score': '9.2'}

    {'top': '10', 'image_src': 'https://p0.meituan.net/movie/230e71d398e0c54730d58dc4bb6e4cca51662.jpg@160w_220h_1e_1c', 'name': '乱世佳人', 'actor': '费雯·丽,克拉克·盖博,奥利维娅·德哈维兰', 'releasetime': '1939-12-15(美国)', 'score': '9.1'}

    写入文件

    得到数据后最后将数据保存到文件,通过JOSN库的dumps()方法可以实现字典的序列化。因为这里要处理中文,将ensure_ascii参数设为False就可以保证输出结果是中文形式而不是Unicode编码。代码如下:

    def write_to_file(content):

    with open('result.txt','a',encoding='utf-8') as f:

    f.write(json.dumps(content,ensure_ascii = False) + '')

    f.close()

    其中open()指定写入方式为a尾部写入,这是因为此时是for循环写入数据,如果用w写入只会保留最后一组的数据。或者在这之前打开文件,等写入完数据后再关闭也可以。

    通过调用write_to_file()方法即可实现将字典写入到文本文件的过程。

    main方法

    实现main()方法接收一个offset值作为偏移量,然后构造URL进行爬取。代码如下:

    def main(offset):

    url = "http://maoyan.com/board/4?offset=" + str(offset)

    html = get_page(url)

    for item in parse_page(html):

    print(item)

    write_of_file(item)

    多线程分页爬取

    上面实现了给main()传入一个offset值爬取单页10个电影的数据,接下来使用多线程来抓取整个TOP100的电影数据。

    from multiprocessing import Pool # 引入多线程模块

    if __name__ == '__main__':

    #创建线程池

    pool = Pool()

    # pool.map第一个参数是函数,第二个参数是传递给函数的参数

    pool.map(main,[i*10 for i in range(10)])

    Pool.map()函数第一个参数是函数,第二个参数是传递给函数的参数,在上面代码中是一个迭代器,将迭代器中的数字作为参数依次传入函数中。

    注意:使用多线程爬取会导致最后写入到文件内的电影数据(top值)是乱序的,如需保证爬取到的电影信息写入到文件是按照top值排序的,放弃多线程将代码改为:

    import time #引入时间模块

    if __name__ == '__main__':

    for i in range(10):

    main(offset=i * 10)

    time.sleep(1)

    为突破猫眼反爬虫机制(速度过快会无响应),上面代码增加了一个延时等待。

    大功告成!完整代码如下:

    import requests

    import re

    import time

    import json

    from requests.exceptions import RequestException

    from multiprocessing import Pool

    def get_page(url):

    headers = {

    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'

    }

    response = requests.get(url,headers = headers)

    try:

    if response.status_code == 200:

    return response.text

    return None

    except RequestException:

    print("request error")

    return None

    def parse_page(html):

    pattern = re.compile('.*?board-index.*?>(d+).*?data-src="(.*?)".*?name.*?a.*?>(.*?).*?star">(.*?)'

    + '.*?releasetime">(.*?).*?integer">(.*?).*?fraction">(.*?).*?',re.S) #re.S使.能匹配任意字符

    items = pattern.findall(str(html))

    for item in items:

    yield {

    'top':item[0],

    'image_src':item[1],

    'name':item[2],

    'actor':item[3].strip()[3:] if len(item[3]) > 3 else '',

    'releasetime':item[4].strip()[5:],

    'score':item[5] + item[6]

    }

    def write_to_file(content):

    with open('result.txt','a',encoding='utf-8') as f:

    f.write(json.dumps(content,ensure_ascii = False) + '')

    f.close()

    def main(offset):

    url = "http://maoyan.com/board/4?offset=" + str(offset)

    html = get_page(url)

    for item in parse_page(html):

    print(item)

    write_to_file(item)

    # 如需保证电影顺序,则放弃使用多线程

    # if __name__ == '__main__':

    # for i in range(10):

    # main(offset=i * 10)

    # time.sleep(1)

    if __name__ == '__main__':

    pool = Pool()

    pool.map(main,[i*10 for i in range(10)])

    相关文章

      网友评论

        本文标题:抓取猫眼TOP100电影信息

        本文链接:https://www.haomeiwen.com/subject/kqnmjqtx.html