豆瓣电影数据爬取实战

目录

1.简介

        1.1项目背景和目标

        1.2技术栈概述

数据爬取流程

发送 HTTP 请求获取网页内容

提取电影详情页链接

获取电影详情页内容

解析电影详情页并提取相关信息

关键函数详解

index_url(url, header):获取指定 URL 的页面内容

parse_url(html):从页面内容中提取电影详情页的链接

parse_detral(detail_html):从电影详情页的 HTML 内容中提取电影相关信息

主函数实现

main():调用关键函数实现整个流程

日志记录与异常处理

使用 logging 库记录日志信息

异常处理的重要性与实践

扩展功能

数据存储:将爬取的数据存储到数据库或文件中

异步爬虫:使用异步请求库提高效率

反爬虫应对策略:处理反爬虫机制

总结与心得

项目完成情况总结

对爬虫开发的体会与建议


1.简介

        1.1项目背景和目标

          项目目标:从豆瓣电影网站上爬取正在热映电影的相关信息:

(网址:https://movie.douban.com/cinema/nowplaying/liuzhou/),这里我以柳州为例子,包括电影名字、演员、类型、语言、上映日期和简介,并且存储到mongodb数据库中

        1.2技术栈概述

           技术栈:依赖 requests 库发送 HTTP 请求,logging 库记录日志信息,re 库进行正则表达式匹配

2.数据爬取流程

        2.1 前期准备工作

                当进行数据爬取项目时,我们需要导入一些常用的库和模块来辅助我们完成任务。以下是一些常见的库和模块:

  1. requests:用于发送HTTP请求并获取网页内容。
  2. logging:用于记录日志信息,方便调试和追踪程序运行情况。
  3. re:提供正则表达式匹配功能,可以方便地从文本中提取所需信息。
  4. pymongo:用于连接MongoDB数据库,并进行数据的插入、查询等操作。
import requests
import logging
import re
from pymongo import MongoClient

 配置日志记录是在编程过程中非常重要的一环,它可以帮助我们追踪程序的运行情况、排查问题,并且记录下程序的运行日志

logging.basicConfig(level=logging.INFO, format='%(asctime)s = %(levelname)s: %(message)s')

        2.2 发送 HTTP 请求获取网页内容

                首先我们先定义好根网址以及请求头用来模拟浏览器,先想办法获取到根网址的html代码,才能对后续操作做好准备,图中的index_url是一个通用的解析函数,可以进行根网址以及电影详情链接的解析

# 定义豆瓣电影正在热映页面的 URL
BASE_URL = 'https://movie.douban.com/cinema/nowplaying/liuzhou/'

# 设置 HTTP 请求头,模拟浏览器发送请求
header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'
}

# 获取指定 URL 的页面内容
def index_url(url, header):
    logging.info('scrape %s...', url)
    try:
        response = requests.get(url=url, headers=header)
        if response.status_code == 200:
            response.encoding = 'utf-8'
            return response.text
        else:
            logging.info('获取失败')
            return ''
    except requests.RequestException:
        logging.error('error occurred while scraping %s', url)
        return ''

                

3.提取电影详情页链接

        将上述获得根网址的html代码作为参数传到此函数中,图中代码的作用是利用正则表达式在根目录的html代码中寻找到每部电影的详情链接,得到一个detail_url列表

# 从页面内容中提取电影详情页的链接
def parse_url(html):
    pattern = re.compile('<li class="poster".*?<a href="(.*?)".*?>.*?</li>', re.S)
    items = re.findall(pattern, html)
    for i in items:
        detail_url = i
        logging.info('得到详情链接%s', detail_url)
        yield detail_url

4.获取电影详情页内容解析电影详情页并提取相关信息

        将解析得到的详情页的html代码作为参数传递到下图函数中,使用正则表达式寻找我们想要的信息

# 从电影详情页的 HTML 内容中提取电影相关信息
def parse_detral(detail_html):
    movie_name_pattern = re.compile('<span\sproperty="v:itemreviewed">(.*?)</span>', re.S)
    actor_pattern = re.compile('<a href=".*?" rel="v:starring">(.*?)</a>', re.S)
    movie_type_pattern = re.compile('<span property="v:genre">(.*?)</span>', re.S)
    language_pattern = re.compile('语言:</span>(.*?)<br/>', re.S)
    public_date_pattern = re.compile('<span property="v:initialReleaseDate" content=".*?">(.*?)</span>', re.S)
    intro_pattern = re.compile('<span property="v:summary" class="">(.*?)</span>', re.S)

    movie_name = re.search(movie_name_pattern, detail_html).group(1).strip() if re.search(
        movie_name_pattern, detail_html) else None
    actor = re.findall(actor_pattern, detail_html) if re.findall(actor_pattern, detail_html) else None
    movie_type = re.findall(movie_type_pattern, detail_html) if re.findall(movie_type_pattern, detail_html) else None
    language = re.search(language_pattern, detail_html).group(1).strip() if re.search(
        language_pattern, detail_html) else None
    public_date = re.search(public_date_pattern, detail_html).group(1).strip() if re.search(
        public_date_pattern, detail_html) else None
    intro = re.search(intro_pattern, detail_html).group(1).strip() if re.search(
        intro_pattern, detail_html) else None

    return {
        'movie_name': movie_name,
        'actor': actor,
        'movie_type': movie_type,
        'language': language,
        'public_date': public_date,
        'intro': intro
    }

4.数据库连接以及相关配置

        对数据库进行连接,在下面代码中可以修改自己的数据库名字以及集合名称,localhost就是自己电脑的ip,无需修改,需要注意的是,mongodb数据库的端口号是27017,也是不需要修改的

# MongoDB 连接配置
MONGO_HOST = 'localhost'
MONGO_PORT = 27017
MONGO_DB = 'douban_movie'
MONGO_COLLECTION = 'movies'

# 连接 MongoDB 数据库
client = MongoClient(MONGO_HOST, MONGO_PORT)
db = client[MONGO_DB]
collection = db[MONGO_COLLECTION]

5.主函数的实现

        main():调用关键函数实现整个流程

# 主函数
def main():
    html = index_url(BASE_URL, header)
    detail_urls = parse_url(html)
    for detail_url in detail_urls:
        try:
            detail_html = index_url(detail_url, header)
            if detail_html:
                data = parse_detral(detail_html)
                logging.info("得到电影相关信息:%s", data)
                # 将电影信息插入数据库
                collection.insert_one(data)
            else:
                logging.info("获取电影详情失败:%s", detail_url)
        except requests.exceptions.Timeout:
            logging.info("获取电影详情失败:%s", detail_url)
            continue

if __name__ == '__main__':
    main()

6.关键函数详解

        index_url(url, header):获取指定 URL 的页面内容

        parse_url(html):从页面内容中提取电影详情页的链接

        parse_detral(detail_html):从电影详情页的 HTML 内容中提取电影相关信息

7.完整代码过程

       完整代码展示如下:

# 导入需要的库和模块
import requests
import logging
import re
from pymongo import MongoClient

# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s = %(levelname)s: %(message)s')

# 定义豆瓣电影正在热映页面的 URL
BASE_URL = 'https://movie.douban.com/cinema/nowplaying/liuzhou/'

# 设置 HTTP 请求头,模拟浏览器发送请求
header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'
}

# 获取指定 URL 的页面内容
def index_url(url, header):
    logging.info('scrape %s...', url)
    try:
        response = requests.get(url=url, headers=header)
        if response.status_code == 200:
            response.encoding = 'utf-8'
            return response.text
        else:
            logging.info('获取失败')
            return ''
    except requests.RequestException:
        logging.error('error occurred while scraping %s', url)
        return ''

# 从页面内容中提取电影详情页的链接
def parse_url(html):
    pattern = re.compile('<li class="poster".*?<a href="(.*?)".*?>.*?</li>', re.S)
    items = re.findall(pattern, html)
    for i in items:
        detail_url = i
        logging.info('得到详情链接%s', detail_url)
        yield detail_url

# 从电影详情页的 HTML 内容中提取电影相关信息
def parse_detral(detail_html):
    movie_name_pattern = re.compile('<span\sproperty="v:itemreviewed">(.*?)</span>', re.S)
    actor_pattern = re.compile('<a href=".*?" rel="v:starring">(.*?)</a>', re.S)
    movie_type_pattern = re.compile('<span property="v:genre">(.*?)</span>', re.S)
    language_pattern = re.compile('语言:</span>(.*?)<br/>', re.S)
    public_date_pattern = re.compile('<span property="v:initialReleaseDate" content=".*?">(.*?)</span>', re.S)
    intro_pattern = re.compile('<span property="v:summary" class="">(.*?)</span>', re.S)

    movie_name = re.search(movie_name_pattern, detail_html).group(1).strip() if re.search(
        movie_name_pattern, detail_html) else None
    actor = re.findall(actor_pattern, detail_html) if re.findall(actor_pattern, detail_html) else None
    movie_type = re.findall(movie_type_pattern, detail_html) if re.findall(movie_type_pattern, detail_html) else None
    language = re.search(language_pattern, detail_html).group(1).strip() if re.search(
        language_pattern, detail_html) else None
    public_date = re.search(public_date_pattern, detail_html).group(1).strip() if re.search(
        public_date_pattern, detail_html) else None
    intro = re.search(intro_pattern, detail_html).group(1).strip() if re.search(
        intro_pattern, detail_html) else None

    return {
        'movie_name': movie_name,
        'actor': actor,
        'movie_type': movie_type,
        'language': language,
        'public_date': public_date,
        'intro': intro
    }

# MongoDB 连接配置
MONGO_HOST = 'localhost'
MONGO_PORT = 27017
MONGO_DB = 'douban_movie'
MONGO_COLLECTION = 'movies'

# 连接 MongoDB 数据库
client = MongoClient(MONGO_HOST, MONGO_PORT)
db = client[MONGO_DB]
collection = db[MONGO_COLLECTION]

# 其他代码保持不变...

# 主函数
def main():
    html = index_url(BASE_URL, header)
    detail_urls = parse_url(html)
    for detail_url in detail_urls:
        try:
            detail_html = index_url(detail_url, header)
            if detail_html:
                data = parse_detral(detail_html)
                logging.info("得到电影相关信息:%s", data)
                # 将电影信息插入数据库
                collection.insert_one(data)
            else:
                logging.info("获取电影详情失败:%s", detail_url)
        except requests.exceptions.Timeout:
            logging.info("获取电影详情失败:%s", detail_url)
            continue


if __name__ == '__main__':
    main()

请注意,这只是一个示例目录,具体的博客目录可以根据你的实际内容和结构进行调整

8.Python爬虫实战项目总结

        在完成这个豆瓣电影数据爬取实战项目的过程中,我获得了以下几点心得体会: 网页数据的获取:通过 requests 库可以方便地获取网页内容,而且可以设置请求头信息来模拟浏览器发送请求,更好地应对反爬虫措施。 数据提取与处理:利用正则表达式可以很好地从网页内容中提取所需的信息,但也需要注意不同网页结构可能导致匹配规则的变化,需要灵活应对。 日志记录的重要性:在项目开发过程中,合理地使用 logging 库记录日志信息可以帮助我们实时监控程序运行情况,快速定位问题并进行调试。 异常处理的必要性:网络请求可能会出现超时、连接断开等异常情况,合理的异常处理能够保证程序的稳定性和健壮性。 总的来说,通过这个实战项目,我对 Python 爬虫的开发流程有了更深入的理解,也更加熟悉了相关的库和模块的使用。同时,我意识到在实际项目中,除了编写代码外,良好的日志记录和异常处理也是非常重要的。希望通过不断地实践和学习,能够进一步提升自己在爬虫领域的技能水平。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值