Python 爬虫(豆瓣top250)-享受爬取信息的快乐

Python 爬虫(豆瓣top250)

一、什么是Python爬虫?

Python爬虫是一种通过模拟浏览器登录,并且抓取信息的程序,抓取的信息保证一定的价值性!

二、Python爬虫的五重架构

1. 调度器 (Scheduler)

调度器是爬虫的"大脑"和"任务中心"。它的主要职责是:

  • URL管理:维护一个待抓取URL的队列(URL Queue)和一个已抓取URL的集合(URL Set),防止重复抓取。
  • 任务分发:当下载器空闲时,从URL队列中取出一个URL,并将其分配给下载器去执行抓取任务。
  • 启动入口:接收爬虫最初的启动URL。

在简单的爬虫中,一个列表或集合就可以充当调度器。在分布式爬虫中,通常会使用像Redis这样的中间件来实现一个共享的、分布式的URL队列。

2. 下载器 (Downloader)

下载器是"体力劳动者",负责与目标网站进行网络交互。它的职责是:

  • 获取URL:从调度器那里接收一个URL。
  • 发送请求 :使用HTTP/HTTPS协议,向该URL对应的服务器发送请求(Request)。为了反反爬,这一步通常需要伪装请求头(Headers),比如User-AgentCookies等。
  • 获取响应:接收服务器返回的响应(Response),这通常是HTML、JSON或其他格式的原始数据。
  • 返回数据:将获取到的响应数据交给解析器进行处理。

常用的库requests, aiohttp, urllib

3. 解析器 (Parser)

解析器是"数据提取师",负责从下载器返回的原始数据中提取有价值的信息。它的职责是:

  • 解析内容:接收下载器传来的响应数据(如HTML字符串)。
  • 数据提取:使用特定的解析规则(如XPath、CSS选择器、正则表达式)从页面中提取出需要的目标数据(例如:商品标题、价格、新闻内容等)。
  • URL发现:在页面中寻找新的、符合规则的URL链接,并将这些新发现的URL交给调度器,用于后续的抓取。

常用的库BeautifulSoup, lxml, PyQuery, parsel

4. 数据存储/管道 (Item Pipeline)

数据存储模块是"仓库管理员",负责处理和保存解析器提取出的数据。它的职责是:

  • 数据清洗:对提取出的原始数据进行清洗、格式化和验证。
  • 数据持久化 :将处理干净的数据保存到指定的目的地,例如:
    • 文件:CSV, JSON, XML等。
    • 关系型数据库:MySQL, PostgreSQL。
    • 非关系型数据库:MongoDB, Redis。

这个模块通常被设计成一个"管道 ",数据项 可以流经多个处理单元,每个单元完成一项特定的任务(如清洗、去重、存入数据库等)。

5. 爬虫引擎 (Engine)

引擎是整个爬虫系统的"心脏"和"总指挥"。它负责协调和驱动其他所有模块协同工作,控制整个系统的数据流。

  • 控制流程:启动爬虫,向调度器索要第一个URL,然后将其交给下载器。
  • 数据流转:将下载器返回的响应交给解析器,将解析器提取的数据交给数据存储管道,将解析器发现的新URL交给调度器。
  • 异常处理:处理在爬取过程中可能出现的各种异常(如请求超时、解析错误等)。
  • 并发控制:在高级爬虫框架中,引擎还负责管理并发请求,通过多线程、多进程或异步协程来提升爬取效率。

三、网址分析

基础网址: https://movie.douban.com/top250?start=0\&filter=

规律总结

复制代码
第一页:https://movie.douban.com/top250?start=0&filter=
第二页:https://movie.douban.com/top250?start=25&filter=
第三页:https://movie.douban.com/top250?start=50&filter=
...
第十页:https://movie.douban.com/top250?start=225&filter=

可以发现,每一个网页有25个电影数目,每个一页都有一个参数start=??代表从第几部电影开始!例如最后一页是:start=225,本页从第226布电影开始,到250部!所以我们只需要改变start参数的值,就可以循环访问到全部的网页。


1. 电影板块分析

经过分析,不难发现在此页面的中,每一个电影都有一个div class="item",所以我们要获取全部的电影列表的第一步就是将所以的class = "item"div获取下来,然后再进行更见详细的消息提取。


2. 电影名字分析

通过分析可以得知,每一部电影的标题一般位于一个div::hdspan行中,类为titleother,并再第一个title后面的title会带有&nbsp禁止换行的标识,在数据清洗的时候应该去掉。


3. 其余信息

可以发现,其余的信息:导演、演员、电影发布时间、地点、电影类型、评分、名言等 ,全部都位于bddiv


四、单页爬虫

1. 设置一些基本信息

Import一些必要的模块

python 复制代码
import requests # 用于HTTP请求
from bs4 import BeautifulSoup # 用户HTML文件解析
import lxml # 提供更快的解析
import time #用于延迟访问,更像人类

设置好HTTP协议的请求头的属性

python 复制代码
# 使用一个标准的请求头
headers = {
    # 用户代理,模拟不同浏览器和操作系统
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',

    # 接受的内容类型
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',

    # 接受的语言
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',

    # 接受的编码格式 使用HTML文件解析的时候,不要使用这个
    # 'Accept-Encoding': 'gzip, deflate, br',

    # 保持连接
    'Connection': 'keep-alive',

    # (可选) 从哪个页面跳转而来,对于防盗链的网站很重要
    'Referer': 'https://www.google.com/',

    # (可选) Cookie,处理需要登录或有用户状态的网站
    'Cookie': 'bid=AbmGIJqppvU; _pk_id.100001.4cf6=b4778cf8691672a8.1758706472.; __utma=30149280.652947316.1758706472.1758706472.1758706472.1; __utmc=30149280; __utmz=30149280.1758706472.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=223695111.1131007441.1758706472.1758706472.1758706472.1; __utmc=223695111; __utmz=223695111.1758706472.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __yadk_uid=1xW2nD4u1Q0yUFFSrmDKJAYI8VMuHO20; ll="118304"'
}

如果你使用了VPN,你可以添加一个设置,禁用VPN

python 复制代码
# 禁用代理,避免网络问题
proxies = {
    'http': None,
    'https': None,
}

2. 程序主体

下面设置程序的入口main函数

python 复制代码
# 主程序
def main():
    # 需要访问的网站 后面可以动态修改访问其它的页面
    url = r"https://movie.douban.com/top250?start=0&filter="
    parse_page(url)


if __name__ == '__main__':
    main()

单页网站爬取函数

python 复制代码
def parse_movie_info(info_div, count):
    try:
        # 获取标题
        # 获取info 下的所有 class 为 title 的sapn
        title_spans = info_div.find_all('span', attrs={'class': 'title'})
        # 获取info 下的所有 class 为 other 的sapn
        other_span = info_div.find('span', attrs={'class': 'other'})
        # 获取中文名
        chinese_title = title_spans[0].get_text()
        # 获取英文名字,并且处理一些文字
        english_title = 'None'
        if len(title_spans) > 1:
            english_title = title_spans[1].get_text().replace('\xa0/\xa0', '').strip()
        # 获取别名
        other_title = other_span.text.replace('\xa0/\xa0', '').strip()

        # 获取导演与演员信息以及电影信息
        movie_attributes = info_div.select_one('div.bd p')
        # 去掉</br>
        if movie_attributes.br:
            movie_attributes.br.replace_with('|||')
        text = movie_attributes.get_text().replace('\xa0', '').replace('"', '')
        parts = text.split('|||')
        actors_info, attribute_info = [' '.join(part.split()) for part in parts]

        # 获取评分
        bd_div = info_div.find('div', attrs={'class': 'bd'})
        rating = bd_div.find('span', attrs={'class': 'rating_num'}).get_text()
        review_element = None
        for span in bd_div.find_all('span'):
            if span.text and '人评价' in span.text:
                review_element = span.text
                review_element = review_element.replace('人评价', '')
                break

        # 获取名言
        quote_element = (bd_div.find('p', attrs={'class': 'quote'}).find('span').get_text()) \
            if bd_div.find('p', attrs={'class': 'quote'}) else None
        
        # 存入数据
        save_csv([count, chinese_title, english_title, other_title,
                           actors_info, attribute_info, rating, review_element, quote_element])

        print(f"----------------------- {count} -----------------------")
        print(f"中文名:{chinese_title} \n英文名:{english_title} \n别名:{other_title}")
        print(f"{actors_info}")
        print(f"电影信息:{attribute_info}")
        print(f"评分:{rating} 评价人数:{review_element}")
        print(f"名言:{quote_element}")
        print(f"-------------------------------------------------")
    except Exception as e:
        print(f"解析单个网页信息出错:{e}")
  • requests.get获取网页的响应,包括一下HTTP响应信息。

信息解析函数

python 复制代码
def parse_page(url, page_number):
    try:
        # 获取响应
        response = requests.get(url, headers=headers, proxies=proxies, timeout=5)

        if response.status_code == 200:
            print(f"请求成功,开始解析第 {page_number} 页网址")

            # 解析响应文本,使用HTML格式
            soup =  BeautifulSoup(response.text, 'lxml')

            # 获取全部电影数目
            movie_list = soup.find_all('div', attrs={'class': 'item'})

            # 遍历每一个电影数目,获取其中的信息
            count = (page_number - 1) * 25 + 1

            for movie_item in movie_list:
                # 获取电影的整个信息
                info_div = movie_item.find('div', attrs={'class': 'info'})
                parse_movie_info(info_div, count)

                count += 1
                time.sleep(0.1)  # 增加一个小的延迟,模拟人类行为,是个好习惯
        else:
            print(f"请求失败!状态码:{response.status_code}")
    except requests.RequestException as e:
        print(f"请求错误:{e}")

五、多页爬虫

上面我们已经写了简单的单页爬虫,下面我们只需要完善一下功能就可以通过url的变化来爬取全部的网页了,综合代码如下(只需要修改我们的主程序):

python 复制代码
def main():
    # 初始化csv
    csv_init()

    # 循环1到10页网址
    for i in range(0, 10): # 所以这里的网址的start参数依次是:0,25,50...225
        url = 'https://movie.douban.com/top250?start=' + f'{i}' + '&filter='
        parse_page(url, i + 1)

if __name__ == '__main__':
    main()

添加数据保存

python 复制代码
def csv_init():
    with open('movie.csv', 'w', newline='', encoding='utf-8-sig') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(['序号', '中文名', '英文名', '别名', '演员信息', '电影信息', '评分', '评价人数', '名言'])

# 储存数据
def save_csv(info):
    with open('movie.csv', 'a', newline='', encoding='utf-8-sig') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(info)

分别写入mainparse_movie_info函数中~


六、结语

如果你有其它编程语言的基础,我相信你学Python是十分的快速的,同时如果你要学习Python爬虫,你必须还要掌握一些HTML、CSS、JavaScript 知识,这样的学习起来也是轻松的,同时学习一些正则表达式更加好!我也是一个小白,希望大家都可以在自己的学习道路上有所收获!

相关推荐
Dxy12393102162 小时前
Python对图片进行加密,js前端进行解密
前端·javascript·python
jie*3 小时前
小杰深度学习(two)——全连接与链式求导
图像处理·人工智能·pytorch·python·深度学习·分类·回归
CodeCraft Studio3 小时前
借助Aspose.Email,使用 Python 将 EML 转换为 MHTML
linux·服务器·python·aspose·email·mhtml·eml
SkylerHu3 小时前
MacOS 使用ssh2-python报错ImportError: dlopen ... _libssh2_channel_direct_tcpip_ex
python·macos·ssh2
计算机软件程序设计11 小时前
基于Python的二手车价格数据分析与预测系统的设计与实现
开发语言·python·数据分析·预测系统
mortimer11 小时前
Traceback 模块:`format_exc` 和 `format_exception` 傻傻分不清
python
Cherry Zack12 小时前
了解Django模型,从基础到实战
python·学习·django
qq74223498412 小时前
语音识别:PyAudio、SoundDevice、Vosk、openai-whisper、Argos-Translate、FunASR(Python)
python·whisper·语音识别
曾经的三心草13 小时前
OpenCV2-图像基本操作-阈值与平滑处理-形态学-梯度运算
python·opencv