Skip to content

爬虫-豆瓣电影Top250

难度:⭐⭐

1. 题目描述

题目描述

爬虫实战,爬取 豆瓣电影 Top250

2. 关键点

  • 正则表达式

3. 代码实现

点击显示代码
python
import re
import requests


def get_movie_top250_one_page(start):
    """爬取豆瓣电影 top250
    分页进行爬取
    """
    url = f'https://movie.douban.com/top250?start={start}&filter='

    # 发现不加 header 获取内容是空;先尝试加 User-Agent;
    # 如果还是空,那就需要加更多的 header
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/'
        '537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36',
    }
    r = requests.get(url, headers=headers)
    html = r.text

    re_s = '<li>(.*?)</li>'
    item_info = re.findall(re_s, html, re.DOTALL)
    # print(item_info[0])

    movies = []
    for item in item_info:
        id_ = re.findall(r'<em class="">(\d+)</em>', item)[0]
        url = re.findall('<a href="(.*)" class="">', item)[0]
        title = re.findall('<span class="title">(.*)</span>', item)[0]
        starring = re.findall('主演: (.*?)[ .].*<br>', item)
        starring = starring[0] if starring else ''
        year = re.findall(r'(\d{4}).*&nbsp;', item)[0]
        score = re.findall(
            '<span class="rating_num" property="v:average">(.*)</span>',
            item)[0]
        print(id_, url, title, starring, year, score)
        movies.append({
            'id': int(id_),
            'url': url,
            'title': title,
            'starring': starring,
            'year': int(year),
            'score': float(score),
        })
    return movies


def get_movie_top250_all_page():
    """爬取所有页"""
    movies = []
    for page in range(10):
        start = page * 25
        movies.extend(get_movie_top250_one_page(start))
        # break
    return movies


def print_prettytable(movies):
    """以 table 格式输出"""
    from prettytable import PrettyTable
    tb = PrettyTable()
    tb.field_names = ['序号', '电影名', '主演', '上映年代', '豆瓣评分']
    for movie in movies[:10]:
        tb.add_row([
            movie['id'], movie['title'], movie['starring'],
            movie['year'], movie['score']
        ])
    print(tb)


def print_json(movies):
    """以 json 格式输出"""
    import json
    print(json.dumps(movies[:10], indent=4, ensure_ascii=False))


def save_to_csv(movies, fname='top250.csv'):
    """保存为 csv 文件"""
    data = '\n'.join([','.join(map(str, movie.values())) for movie in movies])
    with open(fname, 'w', encoding='utf_8_sig') as f:
        f.write(data)


def save_to_mysql(movies):
    """保存到 mysql 数据库中"""
    pass


if __name__ == '__main__':
    movies = get_movie_top250_all_page()
    print_prettytable(movies)
    print_json(movies)
    save_to_csv(movies)

4. 运行示例

+------+----------------+---------------------+----------+----------+
| 序号 |     电影名     |         主演        | 上映年代 | 豆瓣评分 |
+------+----------------+---------------------+----------+----------+
|  1   |  肖申克的救赎  |     蒂姆·罗宾斯     |   1994   |   9.7    |
|  2   |    霸王别姬    |        张国荣       |   1993   |   9.6    |
|  3   |    阿甘正传    |     汤姆·汉克斯     |   1994   |   9.5    |
|  4   |   泰坦尼克号   | 莱昂纳多·迪卡普里奥 |   1997   |   9.4    |
|  5   | 这个杀手不太冷 |       让·雷诺       |   1994   |   9.4    |
|  6   |    美丽人生    |    罗伯托·贝尼尼    |   1997   |   9.6    |
|  7   |    千与千寻    |        柊瑠美       |   2001   |   9.4    |
|  8   |  辛德勒的名单  |      连姆·尼森      |   1993   |   9.6    |
|  9   |    盗梦空间    | 莱昂纳多·迪卡普里奥 |   2010   |   9.4    |
|  10  | 忠犬八公的故事 |      理查·基尔      |   2009   |   9.4    |
+------+----------------+---------------------+----------+----------+

5. 进阶思考

  1. 完成 save_to_mysql 函数