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

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