0
点赞
收藏
分享

微信扫一扫

Python3爬取豆瓣top250

萨科潘 2022-01-10 阅读 48

        最近因为疫情在宿舍,刚好学习一下崔庆才老师的《python3 网络爬虫开发实战》,其中做到3.4节抓取猫眼电影排行,分析了一下猫眼电影,发现不是有猫眼验证中心,就是页面排行榜的文字信息被加密,想想还是一个小白,现在还不适宜去挑战这种超纲的题,还是一步一个脚印来吧。于是就想着豆瓣也有排行榜,试试它吧,于是发现和之前猫眼的排行机理差不多,刚好锻炼一下对第三章的掌握能力。不说废话了,开始!

        目标站点:

https://movie.douban.com/top250

        页面中显示的有效信息有影片名称、别称、导演、主演、上映时间、地区、评分、图片、分类等信息。

         先抓取首页内容

import requests

def get_one_page(url):
    try:
        headers = {
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
        }
        response = requests.get(url,headers=headers)
        if response.status_code == 200:
           return response.text
        return None
    except RequestException:
        return None
def main():
    url = 'https://movie.douban.com/top250'
    html = get_one_page(url)
    print(html)

main()

        然后分析所需表单内容,所需的内容分别为电影排行序号、电影海报、电影名称、别名(大多数电影有两个以上的名称,但是为了方便(偷懒),就只取了两个)、导演和演员、地区、分类、评分。序号在 <em class=""></em>的节点中,海报在<img>的节点中,电影名称在class=“title”的span中,别名在class=“other”的span中,导演和演员、地区、分类都在class="bd"的div下的p标签中,评分在class="rating_num"的span中。

<div class="item">
    <div class="pic">
        <em class="">2</em>
        <a href="https://movie.douban.com/subject/1291546/">
        <img width="100" alt="霸王别姬"                 src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2561716440.jpg" class="">
        </a>
</div>
<div class="info">
    <div class="hd">
        <a href="https://movie.douban.com/subject/1291546/" class="">
            <span class="title">霸王别姬</span>
                <span class="other">&nbsp;/&nbsp;再见,我的妾  /  Farewell My Concubine</span>
        </a>
        <span class="playable">[可播放]</span>
</div>
<div class="bd">
    <p class="">
                            导演: 陈凯歌 Kaige Chen&nbsp;&nbsp;&nbsp;主演: 张国荣 Leslie Cheung / 张丰毅 Fengyi Zha...<br>
                            1993&nbsp;/&nbsp;中国大陆 中国香港&nbsp;/&nbsp;剧情 爱情 同性
    </p>
    <div class="star">
        <span class="rating5-t"></span>
        <span class="rating_num" property="v:average">9.6</span>
        <span property="v:best" content="10.0"></span>
        <span>1875128人评价</span>
    </div>
    <p class="quote">
        <span class="inq">风华绝代。</span>
    </p>
</div>

        根据分析结果,得出如下正则表达式,同时将结果中一些多余的空格回车清除掉,并将结果存储在字典中:

import requests
import re
from requests.exceptions import RequestException

def get_one_page(url):
    try:
        headers = {
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
        }
        response = requests.get(url,headers=headers)
        if response.status_code == 200:
           return response.text
        return None
    except RequestException:
        return None

def clean_other_title(title):
    title = re.sub('\s','',title)
    return title

def clean_director(director):
    director = re.sub('\n','',director)
    director = re.sub('\s{7}','',director)
    return director

def clean_time(time):
    time = re.sub('\n','',time)
    time = re.sub('\s','',time)
    return time

def clean_breed(breed):
    breed = re.sub('\n','',breed)
    breed = re.sub('\s{2}','',breed)
    return breed

def parse_one_page(html):
    pattern = re.compile('<em\sclass="">(.*?)</em>.*?<img.*?src="(.*?)"'
                          + '.*?<span.*?class="title">(.*?)</span>'
                          + '.*?<span.*?other">&nbsp;/&nbsp;(.*?)</span>'
                          + '.*?class="bd".*?<p\sclass="">(.*?)&nbsp;&nbsp;&nbsp;(.*?)<br>'
                          + '(.*?)&nbsp;/&nbsp;(.*?)&nbsp;/&nbsp;(.*?)</p>'
                          + '.*?<span\sclass="rating_num".*?>(.*?)</span>',re.S)
    items = re.findall(pattern,html)
    for item in items:
        yield {
            'index':item[0],
            'image':item[1],
            'title':item[2],
            'other-title':clean_other_title(item[3]),
            'director':clean_director(item[4]),
            'actor':item[5],
            'time':clean_time(item[6]),
            'country':item[7],
            'breed':clean_breed(item[8]),
            'score':item[9]
        }

def main():
    url = 'https://movie.douban.com/top250?'
    html = get_one_page(url)
    for item in parse_one_page(html):
        print(item)
        
if __name__ == '__main__':
    main()

         按照上述步骤,就可以完整地将第一页内容的信息全部获取到了,部分结果如下:

{'index': '1', 'image': 'https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg', 'title': '肖申克的救赎', 'other-title': '月黑高飞(港)/刺激1995(台)', 'director': '导演: 弗兰克·德拉邦特 Frank Darabont', 'actor': '主演: 蒂姆·罗宾斯 Tim Robbins /...', 'time': '1994', 'country': '美国', 'breed': '犯罪 剧情', 'score': '9.7'}
{'index': '2', 'image': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2561716440.jpg', 'title': '霸王别姬', 'other-title': '再见,我的妾/FarewellMyConcubine', 'director': '导演: 陈凯歌 Kaige Chen', 'actor': '主演: 张国荣 Leslie Cheung / 张丰毅 Fengyi Zha...', 'time': '1993', 'country': '中国大陆 中国香港', 'breed': '剧情 爱情 同性', 'score': '9.6'}
{'index': '3', 'image': 'https://img2.doubanio.com/view/photo/s_ratio_poster/public/p2372307693.jpg', 'title': '阿甘正传', 'other-title': '福雷斯特·冈普', 'director': '导演: 罗伯特·泽米吉斯 Robert Zemeckis', 'actor': '主演: 汤姆·汉克斯 Tom Hanks / ...', 'time': '1994', 'country': '美国', 'breed': '剧情 爱情', 'score': '9.5'}
{'index': '4', 'image': 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p457760035.jpg', 'title': '泰坦尼克号', 'other-title': '铁达尼号(港/台)', 'director': '导演: 詹姆斯·卡梅隆 James Cameron', 'actor': '主演: 莱昂纳多·迪卡普里奥 Leonardo...', 'time': '1997', 'country': '美国 墨西哥 澳大利亚 加拿大', 'breed': '剧情 爱情 灾难', 'score': '9.4'}

        接下来就要做的事情就是获取整个排行榜信息了,现在将网页滚动到最下方,可以发现有分页的列表,点击第2 页,发现页面的URL变成了https://movie.douban.com/top250?start=25,原版第一页网址为 https://movie.douban.com/top250?start=0,可以发现一页显示排行25个,那么top250就有10页,那么请求10次就可以得到排行榜完整信息。每页的网址就由https://movie.douban.com/top250?start=和start的值两部分组成了,代码如下:

def main(start):
    url = 'https://movie.douban.com/top250?start=' + str(start)
    html = get_one_page(url)
    for item in parse_one_page(html):
        print(item)
        
if __name__ == '__main__':
    i = 0
    for i in range(1):
        main(i*25)
        time.sleep(1)

        最后,就是将结果写入文件了。 

def write_to_file(content):
    with open('result.txt','a',encoding='utf-8') as f:
        f.write(json.dumps(content,ensure_ascii=False) + '\n')

        完整代码:

import requests
import re
from requests.exceptions import RequestException
import time
import json

def get_one_page(url):
    try:
        headers = {
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
        }
        response = requests.get(url,headers=headers)
        if response.status_code == 200:
           return response.text
        return None
    except RequestException:
        return None

def clean_other_title(title):
    title = re.sub('\s','',title)
    return title

def clean_director(director):
    director = re.sub('\n','',director)
    director = re.sub('\s{7}','',director)
    return director

def clean_time(time):
    time = re.sub('\n','',time)
    time = re.sub('\s','',time)
    return time

def clean_breed(breed):
    breed = re.sub('\n','',breed)
    breed = re.sub('\s{2}','',breed)
    return breed

def write_to_file(content):
    with open('result.txt','a',encoding='utf-8') as f:
        f.write(json.dumps(content,ensure_ascii=False) + '\n')

def parse_one_page(html):
    pattern = re.compile('<em\sclass="">(.*?)</em>.*?<img.*?src="(.*?)"'
                          + '.*?<span.*?class="title">(.*?)</span>'
                          + '.*?<span.*?other">&nbsp;/&nbsp;(.*?)</span>'
                          + '.*?class="bd".*?<p\sclass="">(.*?)&nbsp;&nbsp;&nbsp;(.*?)<br>'
                          + '(.*?)&nbsp;/&nbsp;(.*?)&nbsp;/&nbsp;(.*?)</p>'
                          + '.*?<span\sclass="rating_num".*?>(.*?)</span>',re.S)
    items = re.findall(pattern,html)
    for item in items:
        yield {
            'index':item[0],
            'image':item[1],
            'title':item[2],
            'other-title':clean_other_title(item[3]),
            'director':clean_director(item[4]),
            'actor':item[5],
            'time':clean_time(item[6]),
            'country':item[7],
            'breed':clean_breed(item[8]),
            'score':item[9]
        }

def main(start):
    url = 'https://movie.douban.com/top250?start=' + str(start)
    html = get_one_page(url)
    for item in parse_one_page(html):
        print(item)
        write_to_file(item)
        
if __name__ == '__main__':
    for i in range(10):
        main(i*25)
        time.sleep(1)
        

举报

相关推荐

0 条评论