Python爬蟲實(shí)戰(zhàn):從零抓取豆瓣電影Top 250并存儲(chǔ)為CSV文件
1. 項(xiàng)目概述從零到一用Python抓取豆瓣電影Top 250最近在整理個(gè)人觀影記錄想看看還有哪些經(jīng)典沒(méi)看過(guò)直接去豆瓣翻Top 250列表太麻煩了一頁(yè)頁(yè)翻還得手動(dòng)記錄。作為一個(gè)Python愛(ài)好者第一反應(yīng)就是寫個(gè)腳本把它“搬”下來(lái)。這個(gè)“Python爬取豆瓣Top 250保存至csv文件”的項(xiàng)目聽(tīng)起來(lái)簡(jiǎn)單但麻雀雖小五臟俱全它幾乎涵蓋了入門級(jí)網(wǎng)絡(luò)爬蟲的所有核心環(huán)節(jié)請(qǐng)求網(wǎng)頁(yè)、解析數(shù)據(jù)、應(yīng)對(duì)反爬、數(shù)據(jù)清洗和持久化存儲(chǔ)。對(duì)于剛學(xué)完P(guān)ython語(yǔ)法想找個(gè)實(shí)戰(zhàn)項(xiàng)目練手的朋友來(lái)說(shuō)這再合適不過(guò)了。它不僅能讓你鞏固requests、BeautifulSoup、pandas這些庫(kù)的使用更能讓你親身體會(huì)從互聯(lián)網(wǎng)上自動(dòng)化獲取并結(jié)構(gòu)化數(shù)據(jù)的完整流程。今天我就把自己實(shí)現(xiàn)這個(gè)項(xiàng)目的詳細(xì)過(guò)程、踩過(guò)的坑以及一些優(yōu)化思路分享出來(lái)你可以跟著一步步操作最終得到一個(gè)包含電影排名、名稱、評(píng)分、評(píng)價(jià)人數(shù)、經(jīng)典臺(tái)詞等信息的整潔CSV文件。2. 核心思路與工具選型解析2.1 項(xiàng)目目標(biāo)與需求拆解我們的核心目標(biāo)是自動(dòng)化獲取豆瓣電影Top 250榜單的所有信息并以結(jié)構(gòu)化的格式CSV保存到本地。拆解開來(lái)需要完成以下幾個(gè)子任務(wù)遍歷所有頁(yè)面Top 250榜單分頁(yè)展示共10頁(yè)每頁(yè)25部電影。我們需要能自動(dòng)拼接出所有頁(yè)面的URL。發(fā)送網(wǎng)絡(luò)請(qǐng)求模擬瀏覽器訪問(wèn)這些頁(yè)面獲取頁(yè)面的HTML源代碼。解析HTML內(nèi)容從復(fù)雜的HTML代碼中精準(zhǔn)地提取出每部電影的排名、名稱、評(píng)分、評(píng)價(jià)人數(shù)、導(dǎo)演、主演、年份、地區(qū)、類型、簡(jiǎn)介、經(jīng)典臺(tái)詞等信息。數(shù)據(jù)清洗與存儲(chǔ)將提取出的文本信息進(jìn)行清洗如去除多余空格、處理缺失值然后以行每部電影和列每個(gè)字段的形式保存到CSV文件中。2.2 技術(shù)棧選擇與理由為什么選擇以下工具這是基于簡(jiǎn)單、高效、社區(qū)支持度高的原則。請(qǐng)求庫(kù)requests。這是Python中最簡(jiǎn)單易用的HTTP庫(kù)相比原生urllib其API設(shè)計(jì)非常人性化幾行代碼就能完成請(qǐng)求發(fā)送和響應(yīng)獲取是爬蟲入門的不二之選。解析庫(kù)BeautifulSoup。我們的目標(biāo)頁(yè)面是靜態(tài)HTML結(jié)構(gòu)相對(duì)清晰。BeautifulSoup提供了非常直觀的“選擇器”方式來(lái)定位元素例如通過(guò)標(biāo)簽名、CSS類名來(lái)查找對(duì)于新手來(lái)說(shuō)學(xué)習(xí)曲線平緩遠(yuǎn)比正則表達(dá)式友好。雖然lxml解析速度更快但BeautifulSoup的易用性在初期更具優(yōu)勢(shì)。數(shù)據(jù)存儲(chǔ)csv模塊與pandas。Python內(nèi)置的csv模塊足以完成基本的寫入操作。但這里我選擇用pandas因?yàn)樗粌H能輕松寫入CSV其DataFrame數(shù)據(jù)結(jié)構(gòu)更便于我們?cè)趦?nèi)存中進(jìn)行數(shù)據(jù)清洗、分析和預(yù)覽是數(shù)據(jù)處理的事實(shí)標(biāo)準(zhǔn)。輔助工具time與User-Agent。time.sleep()用于在請(qǐng)求間插入延遲是尊重網(wǎng)站、避免被封IP的基本禮儀。而設(shè)置隨機(jī)的User-Agent請(qǐng)求頭是為了讓我們的請(qǐng)求看起來(lái)更像來(lái)自不同的瀏覽器是應(yīng)對(duì)基礎(chǔ)反爬的常見(jiàn)手段。注意在開始任何爬蟲項(xiàng)目前務(wù)必查看目標(biāo)網(wǎng)站的robots.txt文件通常是https://www.douban.com/robots.txt和其服務(wù)條款。雖然豆瓣對(duì)Top 250頁(yè)面的爬取相對(duì)寬容用于個(gè)人學(xué)習(xí)但我們必須控制請(qǐng)求頻率嚴(yán)禁高并發(fā)、高頻次訪問(wèn)以免對(duì)服務(wù)器造成壓力。3. 環(huán)境準(zhǔn)備與頁(yè)面結(jié)構(gòu)分析3.1 安裝必要的Python庫(kù)打開你的命令行終端CMD、PowerShell或Terminal使用pip命令安裝我們所需的庫(kù)。建議在虛擬環(huán)境中進(jìn)行。pip install requests beautifulsoup4 pandas如果安裝速度慢可以使用國(guó)內(nèi)鏡像源例如清華源pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests beautifulsoup4 pandas。3.2 分析豆瓣Top 250頁(yè)面結(jié)構(gòu)這是爬蟲最關(guān)鍵的一步?jīng)Q定了我們?nèi)绾螌懡馕龃a。我們打開豆瓣電影Top 250的第一頁(yè)https://movie.douban.com/top250?start0。觀察URL規(guī)律注意URL中的參數(shù)start0。點(diǎn)擊第二頁(yè)URL變?yōu)閟tart25第三頁(yè)是start50。由此可知每頁(yè)顯示25部電影start參數(shù)表示從第幾部開始顯示。我們可以用循環(huán)生成10個(gè)URLstart (page-1) * 25。使用開發(fā)者工具定位元素在瀏覽器頁(yè)面右鍵選擇“檢查”或“審查元素”打開開發(fā)者工具。點(diǎn)擊左上角的箭頭圖標(biāo)或按CtrlShiftC然后去點(diǎn)擊頁(yè)面上第一部電影《肖申克的救贖》的整個(gè)條目區(qū)域。在Elements面板中你會(huì)發(fā)現(xiàn)這個(gè)條目被包裹在一個(gè)div classitem的標(biāo)簽內(nèi)。所有250部電影都被包含在多個(gè)div classitem中。這是我們提取數(shù)據(jù)的循環(huán)單元。在每一個(gè).item內(nèi)部我們?cè)偌?xì)找排名通常在em class標(biāo)簽里。電影名稱在span classtitle里注意可能有中文名和英文名/別名。評(píng)分在span classrating_num里。評(píng)價(jià)人數(shù)在div classstar里的最后一個(gè)span。簡(jiǎn)介Quote在span classinq里但不是每部電影都有。其他信息導(dǎo)演、演員、年份等在div classbd里的p class中這是一段混合的文本需要用字符串方法進(jìn)行分割提取。通過(guò)以上分析我們得到了一個(gè)清晰的“地圖”先找到所有.item然后在每個(gè).item里像查字典一樣根據(jù)特定的CSS類名去提取對(duì)應(yīng)的信息。4. 分步實(shí)現(xiàn)爬蟲核心代碼4.1 構(gòu)建請(qǐng)求頭與實(shí)現(xiàn)單頁(yè)抓取首先我們導(dǎo)入庫(kù)并設(shè)置請(qǐng)求頭這是為了讓自己看起來(lái)更像一個(gè)普通的瀏覽器訪問(wèn)。import requests from bs4 import BeautifulSoup import pandas as pd import time import random # 定義請(qǐng)求頭模擬瀏覽器訪問(wèn) headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 }User-Agent字符串可以從你瀏覽器的開發(fā)者工具Network標(biāo)簽中找到任意一個(gè)請(qǐng)求復(fù)制過(guò)來(lái)。接下來(lái)我們寫一個(gè)函數(shù)fetch_one_page(url)用于獲取單頁(yè)HTML并解析出該頁(yè)25部電影的數(shù)據(jù)。def fetch_one_page(url): 抓取并解析單個(gè)頁(yè)面 # 發(fā)送HTTP GET請(qǐng)求 resp requests.get(url, headersheaders) # 如果狀態(tài)碼不是200拋出異常 resp.raise_for_status() # 設(shè)置正確的編碼豆瓣使用utf-8 resp.encoding utf-8 # 將響應(yīng)文本轉(zhuǎn)換為BeautifulSoup對(duì)象指定解析器為html.parser soup BeautifulSoup(resp.text, html.parser) movie_list [] # 用于存儲(chǔ)當(dāng)前頁(yè)所有電影信息的列表 # 找到當(dāng)前頁(yè)面所有的電影項(xiàng)目每個(gè)div classitem代表一部電影 for item in soup.find_all(div, class_item): movie {} # 用字典存儲(chǔ)一部電影的所有信息 # 1. 提取排名 rank_tag item.find(em) movie[排名] rank_tag.text if rank_tag else # 2. 提取標(biāo)題可能包含中文名和英文名 title_tag item.find(span, class_title) movie[標(biāo)題] title_tag.text if title_tag else # 提取英文名/別名可能在第二個(gè)class為title的span里 other_title_tag title_tag.find_next_sibling(span, class_title) if title_tag else None movie[其他標(biāo)題] other_title_tag.text.replace(/, ).strip() if other_title_tag else # 3. 提取評(píng)分 rating_tag item.find(span, class_rating_num) movie[評(píng)分] rating_tag.text if rating_tag else 0.0 # 4. 提取評(píng)價(jià)人數(shù) star_div item.find(div, class_star) if star_div: # 找到star div下所有的span最后一個(gè)包含評(píng)價(jià)人數(shù) spans star_div.find_all(span) if len(spans) 4: # 例如“1254564人評(píng)價(jià)” 我們需要提取數(shù)字 eval_text spans[3].text movie[評(píng)價(jià)人數(shù)] eval_text.replace(人評(píng)價(jià), ).strip() else: movie[評(píng)價(jià)人數(shù)] 0 else: movie[評(píng)價(jià)人數(shù)] 0 # 5. 提取簡(jiǎn)介經(jīng)典臺(tái)詞/短評(píng) quote_tag item.find(span, class_inq) movie[簡(jiǎn)介] quote_tag.text if quote_tag else # 6. 提取其他信息導(dǎo)演、主演、年份、地區(qū)、類型 # 這些信息都在 div classbd 下的 p class 里是一個(gè)混雜的字符串 bd_p item.find(div, class_bd).find(p, class_) if bd_p: info_text bd_p.get_text(stripTrue) # 獲取純文本并去除兩端空格 # 示例字符串“導(dǎo)演: 弗蘭克·德拉邦特 Frank Darabont 主演: 蒂姆·羅賓斯 Tim Robbins /...\n1994 / 美國(guó) / 犯罪 劇情” # 我們用換行符‘\n’分割字符串 parts info_text.split(\n) if len(parts) 2: # 第一部分包含導(dǎo)演和主演信息 director_actor parts[0] # 第二部分包含年份、地區(qū)、類型 year_country_genre parts[1] # 進(jìn)一步分割導(dǎo)演和主演以“主演:”為界 if 主演: in director_actor: director_part, actor_part director_actor.split(主演:, 1) movie[導(dǎo)演] director_part.replace(導(dǎo)演:, ).strip() movie[主演] actor_part.strip() else: movie[導(dǎo)演] director_actor.replace(導(dǎo)演:, ).strip() movie[主演] # 處理年份、地區(qū)、類型 # 格式可能是“1994 / 美國(guó) / 犯罪 劇情” 用‘/’分割 ycg_parts year_country_genre.split(/) ycg_parts [p.strip() for p in ycg_parts] movie[年份] ycg_parts[0] if len(ycg_parts) 0 else movie[地區(qū)] ycg_parts[1] if len(ycg_parts) 1 else movie[類型] ycg_parts[2] if len(ycg_parts) 2 else else: # 如果分割失敗全部放入一個(gè)字段 movie[其他信息] info_text movie[導(dǎo)演] movie[主演] movie[年份] movie[地區(qū)] movie[類型] else: movie[導(dǎo)演] movie[主演] movie[年份] movie[地區(qū)] movie[類型] movie_list.append(movie) return movie_list這個(gè)函數(shù)是核心中的核心。它完成了從定位元素到提取文本的所有臟活累活。注意其中使用了.find()和.find_all()方法以及.text屬性獲取標(biāo)簽內(nèi)文本。對(duì)于混雜的“其他信息”我們用了字符串分割的方法來(lái)提取結(jié)構(gòu)化字段這是一種非常實(shí)用的技巧。4.2 實(shí)現(xiàn)多頁(yè)遍歷與數(shù)據(jù)匯總單頁(yè)抓取函數(shù)寫好之后遍歷所有頁(yè)面就很簡(jiǎn)單了。我們構(gòu)造所有頁(yè)面的URL循環(huán)調(diào)用fetch_one_page并將結(jié)果合并。def fetch_all_pages(): 抓取所有10頁(yè)數(shù)據(jù) base_url https://movie.douban.com/top250?start{} all_movies [] # 存儲(chǔ)所有250部電影 for page in range(10): # 0到9共10頁(yè) start page * 25 url base_url.format(start) print(f正在抓取第 {page1} 頁(yè)URL: {url}) try: one_page_movies fetch_one_page(url) all_movies.extend(one_page_movies) print(f 成功抓取 {len(one_page_movies)} 部電影信息。) except Exception as e: print(f 抓取第 {page1} 頁(yè)時(shí)出錯(cuò): {e}) # 非常重要的延遲避免請(qǐng)求過(guò)快 # 隨機(jī)睡眠2-5秒模擬人類操作 time.sleep(random.uniform(2, 5)) print(f所有頁(yè)面抓取完成總計(jì) {len(all_movies)} 部電影。) return all_movies這里有兩個(gè)關(guān)鍵點(diǎn)異常處理用try...except包裹單頁(yè)抓取這樣即使某一頁(yè)出錯(cuò)如網(wǎng)絡(luò)波動(dòng)程序也不會(huì)崩潰而是記錄錯(cuò)誤后繼續(xù)抓取下一頁(yè)。請(qǐng)求延遲time.sleep(random.uniform(2, 5))是爬蟲的道德底線。不加延遲的快速連續(xù)請(qǐng)求極易觸發(fā)網(wǎng)站的反爬機(jī)制導(dǎo)致IP被暫時(shí)封禁。隨機(jī)延遲讓請(qǐng)求行為更接近真人瀏覽。4.3 數(shù)據(jù)清洗與保存至CSV抓取到的原始數(shù)據(jù)可能包含一些空白、格式不一致的問(wèn)題用pandas處理起來(lái)非常方便。def save_to_csv(movie_list, filenamedouban_top250.csv): 將電影列表保存為CSV文件 # 將字典列表轉(zhuǎn)換為DataFrame df pd.DataFrame(movie_list) # 數(shù)據(jù)清洗示例 # 1. 確保“評(píng)價(jià)人數(shù)”是數(shù)值類型用于后續(xù)排序或計(jì)算 df[評(píng)價(jià)人數(shù)] pd.to_numeric(df[評(píng)價(jià)人數(shù)], errorscoerce).fillna(0).astype(int) # 2. 確?!霸u(píng)分”是浮點(diǎn)數(shù)類型 df[評(píng)分] pd.to_numeric(df[評(píng)分], errorscoerce).fillna(0.0) # 3. 處理可能的空字符串替換為NaN或特定占位符 df.replace(, pd.NA, inplaceTrue) # 選擇我們想要的列順序 columns_order [排名, 標(biāo)題, 其他標(biāo)題, 評(píng)分, 評(píng)價(jià)人數(shù), 導(dǎo)演, 主演, 年份, 地區(qū), 類型, 簡(jiǎn)介] df df[columns_order] # 保存到CSV文件不保存行索引使用UTF-8編碼確保中文不亂碼 df.to_csv(filename, indexFalse, encodingutf-8-sig) # ‘utf-8-sig’能讓Excel正確識(shí)別編碼 print(f數(shù)據(jù)已成功保存至文件: {filename}) print(df.head()) # 打印前幾行預(yù)覽一下使用utf-8-sig編碼是一個(gè)重要技巧它會(huì)在文件開頭添加一個(gè)BOM字節(jié)順序標(biāo)記這樣用微軟Excel打開CSV文件時(shí)中文字符就不會(huì)顯示為亂碼。如果你只用文本編輯器或Python處理用utf-8也可以。4.4 主函數(shù)與完整腳本整合最后我們將所有功能整合到一個(gè)主函數(shù)中。def main(): print(開始抓取豆瓣電影Top 250...) all_movies fetch_all_pages() if all_movies: save_to_csv(all_movies) print(任務(wù)完成) else: print(未抓取到任何數(shù)據(jù)。) if __name__ __main__: main()將上述所有代碼塊按順序保存到一個(gè).py文件中例如douban_top250_spider.py在終端運(yùn)行python douban_top250_spider.py就可以看到程序開始一頁(yè)頁(yè)抓取并在完成后生成一個(gè)douban_top250.csv文件。5. 進(jìn)階優(yōu)化與反爬策略應(yīng)對(duì)基礎(chǔ)的爬蟲寫好了但它還很脆弱。在實(shí)際運(yùn)行中你可能會(huì)遇到各種問(wèn)題。下面分享一些進(jìn)階優(yōu)化和應(yīng)對(duì)策略。5.1 處理動(dòng)態(tài)加載與請(qǐng)求失敗我們當(dāng)前的腳本假設(shè)每次請(qǐng)求都能成功。但網(wǎng)絡(luò)是不穩(wěn)定的。增加重試機(jī)制可以使用requests的適配器或自己寫循環(huán)在請(qǐng)求失敗時(shí)如遇到連接超時(shí)、狀態(tài)碼5xx重試幾次。import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry def create_session(retries3, backoff_factor0.5): session requests.Session() retry_strategy Retry( totalretries, backoff_factorbackoff_factor, # 重試等待時(shí)間{backoff factor} * (2 ** ({retry number} - 1)) status_forcelist[500, 502, 503, 504] # 遇到這些狀態(tài)碼才重試 ) adapter HTTPAdapter(max_retriesretry_strategy) session.mount(http://, adapter) session.mount(https://, adapter) return session # 使用session代替直接的requests.get session create_session() resp session.get(url, headersheaders, timeout10) # 設(shè)置超時(shí)使用代理IP如果你的IP因請(qǐng)求過(guò)快被封可能需要使用代理IP池。但這對(duì)于豆瓣Top 250這種低頻、禮貌的爬取通常不是必須的優(yōu)先級(jí)低于控制頻率。5.2 數(shù)據(jù)解析的健壯性提升網(wǎng)頁(yè)結(jié)構(gòu)可能會(huì)微調(diào)我們的解析代碼不能太“硬編碼”。使用更靈活的CSS選擇器BeautifulSoup支持CSS選擇器語(yǔ)法soup.select()有時(shí)比f(wàn)ind更簡(jiǎn)潔。# 例如提取所有電影項(xiàng)目 items soup.select(div.item) # 提取單個(gè)電影的標(biāo)題 title item.select_one(span.title).text增加字段缺失的容錯(cuò)處理我們?cè)诨A(chǔ)代碼中已經(jīng)用了if tag:的判斷這是很好的習(xí)慣??梢赃M(jìn)一步為每個(gè)字段提供默認(rèn)值。5.3 將數(shù)據(jù)存入數(shù)據(jù)庫(kù)可選CSV文件適合一次性分析和存檔但如果數(shù)據(jù)需要頻繁查詢或更新存入SQLite或MySQL數(shù)據(jù)庫(kù)是更好的選擇。import sqlite3 def save_to_sqlite(movie_list, db_namedouban_top250.db): conn sqlite3.connect(db_name) cursor conn.cursor() # 創(chuàng)建表 cursor.execute( CREATE TABLE IF NOT EXISTS movies ( id INTEGER PRIMARY KEY AUTOINCREMENT, rank INTEGER, title TEXT, other_title TEXT, rating REAL, eval_count INTEGER, director TEXT, actors TEXT, year TEXT, region TEXT, genre TEXT, quote TEXT ) ) # 插入數(shù)據(jù) for movie in movie_list: cursor.execute( INSERT INTO movies (rank, title, other_title, rating, eval_count, director, actors, year, region, genre, quote) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , ( movie.get(排名), movie.get(標(biāo)題), movie.get(其他標(biāo)題), movie.get(評(píng)分), movie.get(評(píng)價(jià)人數(shù)), movie.get(導(dǎo)演), movie.get(主演), movie.get(年份), movie.get(地區(qū)), movie.get(類型), movie.get(簡(jiǎn)介) )) conn.commit() conn.close() print(f數(shù)據(jù)已保存至SQLite數(shù)據(jù)庫(kù): {db_name})6. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄在實(shí)際操作中你幾乎一定會(huì)遇到下面這些問(wèn)題。這里是我的排查記錄。6.1 請(qǐng)求被拒絕返回403或418錯(cuò)誤現(xiàn)象requests.get()拋出異常狀態(tài)碼是403 Forbidden或418 I‘m a teapot。原因網(wǎng)站識(shí)別出你是爬蟲程序。最常見(jiàn)的原因是請(qǐng)求頭User-Agent被識(shí)別為Python腳本。解決檢查并完善headers確保User-Agent是有效的瀏覽器字符串??梢远鄿?zhǔn)備幾個(gè)每次請(qǐng)求隨機(jī)選擇一個(gè)。添加更多請(qǐng)求頭模擬更真實(shí)的瀏覽器例如添加Referer告訴服務(wù)器你從哪個(gè)頁(yè)面跳轉(zhuǎn)過(guò)來(lái)、Accept-Language等。headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)..., Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Referer: https://www.douban.com/, Connection: keep-alive, }終極方案使用Selenium模擬瀏覽器。如果網(wǎng)站有復(fù)雜的JavaScript驗(yàn)證或動(dòng)態(tài)加載requests無(wú)法獲取完整頁(yè)面。這時(shí)需要Selenium控制Chrome或Firefox等真實(shí)瀏覽器去渲染頁(yè)面再獲取源碼。但這會(huì)大大增加復(fù)雜度和運(yùn)行時(shí)間僅作為最后手段。6.2 抓取到的數(shù)據(jù)是空的或亂碼現(xiàn)象movie_list為空或者中文顯示為亂碼。原因1網(wǎng)頁(yè)結(jié)構(gòu)已更新原來(lái)的CSS類名或標(biāo)簽路徑失效。排查1重新打開豆瓣Top 250頁(yè)面用開發(fā)者工具再次檢查.item、.title等關(guān)鍵元素的類名是否變化。有時(shí)網(wǎng)站會(huì)進(jìn)行A/B測(cè)試或改版。解決1更新代碼中的選擇器。嘗試使用更通用的選擇器比如item.find(‘span’, attrs{‘class’: ‘title’})。原因2編碼問(wèn)題。排查2打印resp.text的前500個(gè)字符看是否是亂碼。解決2確保設(shè)置了resp.encoding ‘utf-8’。如果不行可以嘗試resp.encoding resp.apparent_encoding讓requests自動(dòng)判斷。6.3 程序運(yùn)行中途停止或變慢現(xiàn)象抓取了幾頁(yè)后程序卡住或報(bào)錯(cuò)停止。原因最可能的原因是觸發(fā)了反爬機(jī)制IP被限流或臨時(shí)封禁。解決立即增加延遲將time.sleep的時(shí)間延長(zhǎng)比如random.uniform(5, 10)。檢查請(qǐng)求頻率確保每頁(yè)之間都有延遲不要在循環(huán)內(nèi)快速連續(xù)請(qǐng)求。暫停程序等待一段時(shí)間如半小時(shí)再運(yùn)行。對(duì)于豆瓣禮貌的、低頻率的爬取通常不會(huì)被永久封禁??紤]使用更分布式的抓取如果是大規(guī)模抓取需要設(shè)計(jì)IP池、用戶代理池但這已超出本入門項(xiàng)目的范疇。6.4 生成的CSV文件在Excel中打開中文亂碼現(xiàn)象用記事本或代碼編輯器打開CSV正常但用Excel打開中文是亂碼。原因Excel默認(rèn)使用系統(tǒng)區(qū)域編碼如中文Windows是GBK打開CSV而我們的文件是UTF-8編碼。解決在保存CSV時(shí)使用encoding‘utf-8-sig’。這個(gè)sig代表BOM它能讓Excel自動(dòng)識(shí)別為UTF-8編碼。6.5 “評(píng)價(jià)人數(shù)”提取失敗或?yàn)?現(xiàn)象評(píng)價(jià)人數(shù)全部是0或空。原因解析div class“star”下的結(jié)構(gòu)不準(zhǔn)確。網(wǎng)頁(yè)結(jié)構(gòu)可能微調(diào)或者我們用的索引不對(duì)。排查與解決打印出star_div的內(nèi)容看看。star_div item.find(div, class_star) print(star_div) # 觀察其內(nèi)部HTML結(jié)構(gòu)找到包含“人評(píng)價(jià)”文本的那個(gè)span標(biāo)簽。 # 可能需要改用更精確的查找方式例如 eval_span star_div.find(span, stringlambda text: text and 人評(píng)價(jià) in text) if eval_span: movie[‘評(píng)價(jià)人數(shù)’] eval_span.text.replace(‘人評(píng)價(jià)’, ‘’)這種基于文本內(nèi)容查找的方式比依賴固定索引更健壯。這個(gè)項(xiàng)目雖然基礎(chǔ)但貫穿了爬蟲的核心邏輯。我建議你在成功運(yùn)行基礎(chǔ)版本后嘗試自己添加新功能比如抓取電影的封面圖片鏈接、影片時(shí)長(zhǎng)或者將評(píng)分和評(píng)價(jià)人數(shù)轉(zhuǎn)換為數(shù)值類型后嘗試用pandas做簡(jiǎn)單的數(shù)據(jù)分析例如評(píng)分分布、哪個(gè)年份的高分電影最多。這些練習(xí)能讓你對(duì)數(shù)據(jù)抓取和處理的流程有更深的體會(huì)。記住爬蟲的世界里耐心和尊重規(guī)則比技術(shù)炫技更重要。

相關(guān)新聞

ABAP同步與異步調(diào)用深度解析:從原理到性能優(yōu)化實(shí)戰(zhàn)

ABAP同步與異步調(diào)用深度解析:從原理到性能優(yōu)化實(shí)戰(zhàn)

1. 從一次性能瓶頸排查說(shuō)起:同步與異步的抉擇 那天下午,業(yè)務(wù)部門的一個(gè)關(guān)鍵報(bào)表程序又卡住了,用戶電話直接打到了我這里。登錄系統(tǒng)一看,一個(gè)標(biāo)準(zhǔn)的 SE38 事務(wù)碼執(zhí)行的報(bào)表,正在后臺(tái)吭哧吭哧地跑,日志顯示…

2026/8/1 13:10:42 閱讀更多
游戲音頻團(tuán)隊(duì)轉(zhuǎn)型生死線:2025年前未部署AI音效引擎的團(tuán)隊(duì),將面臨平均41%人力成本劣勢(shì)(GDC 2024閉門報(bào)告核心結(jié)論)

游戲音頻團(tuán)隊(duì)轉(zhuǎn)型生死線:2025年前未部署AI音效引擎的團(tuán)隊(duì),將面臨平均41%人力成本劣勢(shì)(GDC 2024閉門報(bào)告核心結(jié)論)

更多請(qǐng)點(diǎn)擊: https://kaifayun.com 第一章:游戲音頻團(tuán)隊(duì)轉(zhuǎn)型生死線:2025年前未部署AI音效引擎的團(tuán)隊(duì),將面臨平均41%人力成本劣勢(shì)(GDC 2024閉門報(bào)告核心結(jié)論) GDC 2024閉門報(bào)告指出,AI音效引擎已…

2026/8/1 13:10:42 閱讀更多
寫作反饋循環(huán):如何通過(guò)第一讀者提升內(nèi)容質(zhì)量

寫作反饋循環(huán):如何通過(guò)第一讀者提升內(nèi)容質(zhì)量

1. 寫作困境的本質(zhì):為什么改8遍還是不滿意? 每次打開文檔修改時(shí),我都感覺(jué)自己像個(gè)強(qiáng)迫癥患者。第八次保存文件后,我突然意識(shí)到一個(gè)可怕的事實(shí):我根本分不清哪些是真正需要修改的問(wèn)題,哪些只是我的主觀臆斷?!?/p>

2026/8/1 14:21:09 閱讀更多
基于雙層優(yōu)化的冷熱電多微網(wǎng)儲(chǔ)能配置Matlab實(shí)現(xiàn)

基于雙層優(yōu)化的冷熱電多微網(wǎng)儲(chǔ)能配置Matlab實(shí)現(xiàn)

1. 項(xiàng)目背景與核心價(jià)值 冷熱電多微網(wǎng)系統(tǒng)是當(dāng)前能源互聯(lián)網(wǎng)領(lǐng)域的前沿研究方向,它通過(guò)整合分布式能源、儲(chǔ)能設(shè)備和負(fù)荷需求,實(shí)現(xiàn)區(qū)域內(nèi)能源的高效利用與優(yōu)化調(diào)度。而儲(chǔ)能電站作為系統(tǒng)中的關(guān)鍵緩沖環(huán)節(jié),其配置策略直接影響整個(gè)系統(tǒng)的經(jīng)濟(jì)性和可…

2026/8/1 14:21:09 閱讀更多
僅剩47份!《AI無(wú)縫紋理生產(chǎn)標(biāo)準(zhǔn)白皮書》V2.3內(nèi)部版泄露:涵蓋PBR材質(zhì)合規(guī)性檢測(cè)、Mipmap級(jí)邊緣衰減公式及ISO/IEC 23004-8適配條款

僅剩47份!《AI無(wú)縫紋理生產(chǎn)標(biāo)準(zhǔn)白皮書》V2.3內(nèi)部版泄露:涵蓋PBR材質(zhì)合規(guī)性檢測(cè)、Mipmap級(jí)邊緣衰減公式及ISO/IEC 23004-8適配條款

更多請(qǐng)點(diǎn)擊: https://intelliparadigm.com 第一章:AI圖片無(wú)縫紋理生成的技術(shù)演進(jìn)與行業(yè)挑戰(zhàn) AI驅(qū)動(dòng)的無(wú)縫紋理生成已從早期基于圖像拼接的啟發(fā)式方法,發(fā)展為以擴(kuò)散模型與隱式神經(jīng)表示(INR)為核心的端到端學(xué)習(xí)范式。這…

2026/8/1 14:21:09 閱讀更多
AI寫作爆文拆解實(shí)戰(zhàn)手冊(cè)(附23個(gè)真實(shí)失敗案例復(fù)盤):從提示詞失效到平臺(tái)限流的全鏈路歸因

AI寫作爆文拆解實(shí)戰(zhàn)手冊(cè)(附23個(gè)真實(shí)失敗案例復(fù)盤):從提示詞失效到平臺(tái)限流的全鏈路歸因

更多請(qǐng)點(diǎn)擊: https://kaifayun.com 第一章:AI寫作爆文拆解實(shí)戰(zhàn)手冊(cè)(附23個(gè)真實(shí)失敗案例復(fù)盤):從提示詞失效到平臺(tái)限流的全鏈路歸因 AI寫作不是“輸入提示詞→輸出爆款”的黑箱流程,而是由提示工程、內(nèi)容適…

2026/8/1 14:11:08 閱讀更多
AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O分配PCB板是應(yīng)用材料(Applied Materials)公司生產(chǎn)的一款用于半導(dǎo)體設(shè)備的I/O信號(hào)分配電路板。該型號(hào)(0100-02186)的核心特點(diǎn)如下:專用于Endura等半導(dǎo)體工藝腔室。集成信號(hào)路由與分配功能。連接控制…

2026/8/1 0:09:33 閱讀更多
Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)是日本日清(Nissei)品牌的一款工業(yè)用三相異步電機(jī),適用于自動(dòng)化設(shè)備及通用機(jī)械驅(qū)動(dòng)。該型號(hào)(FFMN-32L-10-T0 40AX)的核心特點(diǎn)如下:三相交流異步電動(dòng)機(jī)。額定…

2026/8/1 0:09:33 閱讀更多
AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O分配PCB板是應(yīng)用材料(Applied Materials)公司生產(chǎn)的一款用于半導(dǎo)體設(shè)備的I/O信號(hào)分配電路板。該型號(hào)(0100-02186)的核心特點(diǎn)如下:專用于Endura等半導(dǎo)體工藝腔室。集成信號(hào)路由與分配功能。連接控制…

2026/8/1 0:09:33 閱讀更多
Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)是日本日清(Nissei)品牌的一款工業(yè)用三相異步電機(jī),適用于自動(dòng)化設(shè)備及通用機(jī)械驅(qū)動(dòng)。該型號(hào)(FFMN-32L-10-T0 40AX)的核心特點(diǎn)如下:三相交流異步電動(dòng)機(jī)。額定…

2026/8/1 0:09:33 閱讀更多