python爬取豆瓣Top250-改進版

老版:Python 爬取內容存入Excel實例
這是之前用python2.7寫的,最近看博友評論,因網頁結構調整和python3的普及,代碼運行後報錯、得不到數據。於是,使用python3重寫了一次,順便做下改進。
網頁解析可以去看下之前的文章,這裏不作贅述。
環境python 3.6.5
所需包安裝pip install requests bs4 lxml openpyxl

1、抓取代碼

先上代碼,後分析

'''
  function:爬取豆瓣top250的電影信息,並寫入Excel文件
  env:python3.6.5
  author:jxc
'''
import requests
import re
from openpyxl import workbook  # 寫入Excel表所用
from bs4 import BeautifulSoup as bs

class Top250:
    def __init__(self):
        #起始地址
        self.start_url = 'https://movie.douban.com/top250'
        #請求頭,瀏覽器模擬
        self.headers = {
            'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
        }
        #爬取頁數
        self.page_num = 10

    '''url拼接'''
    def get_page_url(self):
        n = 0 #第一頁開始,下標0
        while n<self.page_num:
            yield self.start_url+'?start={}&filter='.format(n*25)
            n += 1

    '''獲取頁面源碼'''
    def getHtml(self):
        gu = self.get_page_url() #url生成器
        for url in gu:
            html = requests.get(url,headers=self.headers).content.decode('utf-8')
            yield html

	''''電影數據提取'''
    def getData(self):
        gh = self.getHtml() # html源碼生成器
        for html in gh: # html:網頁源碼
            soup = bs(html, 'lxml')
            for info in soup.find_all('div', class_='info'):
                c_name = info.find('span',class_='title').text.strip() # 得到電影中文名
                message = info.select('div.bd p')[0].text.strip() #得到導演、主演、年份、地區信息
                yat = re.search('[0-9]+.*\/?', message).group().split('/',1) #得到年份、地區、類型信息列表
                year,area,type = yat[0],yat[1].rsplit('/',1)[0],yat[1].rsplit('/',1)[1]#得到年份、地區、類型
                da = re.search('導演.+\s',message).group().strip()+'...' #得到導演、主演混合信息
                director = re.findall('導演:(.+?)\s',da)[0].strip() #得到導演信息
                #得到主演信息,不存在時發生異常,進行異常處理
                try:
                    mainActors = re.findall('主演:(.+?)[.,]+',da)[0].strip()
                except IndexError:
                    mainActors = '暫無主演信息'
                mark_info = info.find('div',class_='star') #得到評分、評價人數混合信息
                score= mark_info.find('span',class_='rating_num').text.strip()#得到評分
                count = re.search('[0-9]+',mark_info.select('span')[3].text).group() #得到評價人數
                #得到簡介,捕捉不存在時的異常
                try:
                    quote = info.select('p.quote span')[0].text.strip()
                except IndexError:
                    quote = '該影片暫時無簡介'
                yield [c_name,year,area,type,director,mainActors,score,count,quote]

    '''保存到excel文件
    :param file_name:文件名
    '''
    def saveToExcel(self,file_name):
        wb = workbook.Workbook()  # 創建Excel對象
        ws = wb.active  # 獲取當前正在操作的表對象
        ws.append(['電影名', '年份', '地區', '劇情類型', '導演', '主演', '評分', '評論人數', '簡介'])
        gd = self.getData() #數據生成器
        for data in gd:
            ws.append(data)
        wb.save(file_name)

if __name__ == '__main__':
    top = Top250()
    try:
        top.saveToExcel('top250.xlsx')
        print('抓取成功')
    except Exception as e:
        print('抓取失敗,原因:%s'%e)

2、代碼要點分析
  • 在獲取各屬性(名稱、導演、主演…)數據時,大量使用了re進行匹配抓取,不熟悉的可以先去看下正則表達式-菜鳥教程
  • rsplit方法,從後往前進行切片。代碼中的rsplit('/',1)意爲從後往前,以/爲切片元素,只切 1 次。
  • re.findall()方法,在前後加上不變的條件,變化的部分使用()包裹,這樣就能直接得到想要的信息,不用再次切片獲取。如代碼中的re.findall('導演:(.+?)\s',da)[0],就能直接得到導演信息。
  • 部分電影無主演或簡介信息,所以使用try...except捕獲異常
3、本次改進的地方
  • 封裝爲類,提高了代碼擴展性
  • 改進了數據抓取方法,提高了代碼效率
  • 使用生成器,實現抓取流水線操作
  • 改進了信息缺失的判斷邏輯,並進行異常處理

歡迎留言討論~

博主其他系列文章:

[1] 【python實用特性】-切片

[2] 【python實用特性】- 迭代、可迭代對象、迭代器

[3] 【python實用特性】- 列表生成式

[4] 【python實用特性】- yield生成器

[5] Python如何爬取動態網頁數據

[6] Python+selenium實現自動爬取實例

[7] Python自動化利器—robobrowser

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章