python抓取豆瓣电影top250信息

1、本博文中代码是转载内容,原文章地址如下:

https://blog.csdn.net/submit66/article/details/78631342?utm_source=blogxgwz1

2、只是在原文代码的基础上稍作修改,添加了一些注释及无关紧要的代码

3、本篇博文涉及知识点如下:

  • ①创建类、创建函数
  • ②创建新线程
  • ③用浏览器检查网页元素
  • ④使用BeautifulSoup获取网页内容
  • ⑤保存网页文本内容到本地文件
  • ⑥下载图片
  • ⑦时间戳

4、代码功能为获取“豆瓣电影top250”页面的摘要信息,详细代码如下(运行环境:win7 + python3)

import requests
from   bs4 import BeautifulSoup
import time
import os
import threading

'''
    定义一个类,属性包含图片的序号、名称以及下载的url
'''
class Picture:
    def __init__(self,pic_num,pic_name,pic_url):
        self.pic_name = pic_name
        self.pic_url = pic_url
        self.pic_num = pic_num

'''
下载图片,因为他比较耗时,所以将其放在子线程中
'''
def download_picture(pic_list):
    #设置图片保存的目录,双反斜杠\\表示转义“\”,实际的作用相当于'douban\pic\'
    file_dir = "douban\pic\\"
    #如果目录不存在,就创建它
    if not os.path.isdir(file_dir):
        os.makedirs(file_dir)
    #下载图片
    for index in range(len(pic_list)):
        try:
            #获取图片列表的单个元素
            pic_url = pic_list[index]
            #设置图片的名字,加上路径是指在路径下创建图片
            filename = file_dir +str(pic_url.pic_num) + '_' + pic_url.pic_name + ".jpg"
            # "wb"表示以二进制写入文件
            # 此处".content"表示以二进制形式返回数据,下载图片及音频时需用此方式
            # 此处的timeout并不是指超过5秒没下载完图片就算超时,而是指5秒内服务器没有响应连接请求就超时
            with open(filename,'wb') as f_open:
                f_open.write(requests.get(pic_url.pic_url,timeout=5).content)
            #因为要下载250个图片,如果长时间等待,看不出程序正常运行,此处每下载10个图片在终端就提示一次
            if pic_url.pic_num % 10 == 0:
                print("已下载%d张图片" % (pic_url.pic_num))
        except:
            print("下载失败!")
            #pass表示不返回任何错误提示
            pass
    print("爬取耗时:",time.time().__float__() - cuttentTime.__float__(),'s')

# param 分页网址的后缀,用于拼接
param = ''
# i 图片下载的个数
i = 1
#时间戳,用于计算程序运行的时间
cuttentTime = time.time()
# pic_list 存储图片名字及图片的下载地址
pic_list = []
while True:
    base_url = 'https://movie.douban.com/top250' + param
    my_response = requests.get(base_url,timeout = 5)
    #若页面返回的状态码不是200,则显示错误
    my_response.raise_for_status()
    response_string = my_response.text
    soup = BeautifulSoup(response_string,'lxml')
    #所有的电影信息都在class为grid_view的ol标签中
    ol_article = soup.find('ol',class_='grid_view')
    #每部电影对应一个li
    li_list = ol_article.find_all('li')
    #获取电影的信息
    for index in range(len(li_list)):
        div_item_info = li_list[index].find('div',class_='info')
        div_hd = div_item_info.find('div',class_='hd')
        div_bd = div_item_info.find('div',class_='bd')
        title_list = div_hd.find_all('span')
        #获取电影名
        title_str = div_hd.find('span',class_='title').getText()
        #获取电影别名
        if div_hd.find('span',class_='other'):
            alias_title_str = div_hd.find('span',class_='other').getText().\
                replace(' ','').replace(' ','').replace('/','',1)
        #获取导演、演员、上映年、电影类型等信息
        content_description_str = div_bd.p.getText().replace('                            ','\t\t').\
            replace('  ','').replace(' / ','/')
        #获取评价星级
        rating_star = div_bd.div.find_all('span')[1].getText()
        #获取评论数量
        comment_str = div_bd.div.find_all('span')[3].getText()
        #获取一句话影评
        if div_bd.find('p',class_='quote'):
            quote_str =  div_bd.find('p',class_='quote').span.getText()
        #将抓取的信息存入本地文档
        file_dir = "douban\\"
        if not os.path.isdir(file_dir):
            os.makedirs(file_dir)
        filename = file_dir + "douban250.txt"
        #此处的"encoding='utf-8'",以utf-8编码创建打开文件,为防止写入文件编码错误
        with open(filename,'a',encoding='utf-8') as f_open:
            f_open.write("\n第%d个电影--------------------------------------" % (i))
            f_open.write("\n\n\t电影名称:" + title_str)
            f_open.write("\n\t电影别名:" + alias_title_str)
            f_open.write("\n\t电影评星:" + rating_star)
            f_open.write("\n\t评价数量:" + comment_str)
            f_open.write("\n\t电影一句话总结:" + quote_str)
            f_open.write("\n\t电影大致内容信息:" + content_description_str)
        #获取图片信息
        div_pic = li_list[index].find('div',class_='pic')
        pic_list.append(Picture(i,div_pic.a.img.get('alt'),div_pic.a.img.get('src')))
        i += 1
    #获取分页信息
    div_paginator = soup.find('div',class_='paginator')
    next_url = div_paginator.find('span',class_='next')
    #如果没有link则退出while循环,用来判断已经到达最后一页
    if not next_url.link:
        break
    # 获取link的某个属性,可以使用get方法
    param = next_url.link.get('href')

'''
   在所有数据内容爬取完毕后开始一个新的线程下载图片,这里还非得用threading模块了,
   因为它开启的派生线程在运行时候,主线程不会退出,直至派生线程执行完毕
   但是如果派生线程被设置为守护线程,即设置setDaemon为true的话,
   主线程退出派生线程也就不执行了(但是这个不是我们想要的)
   如果直接使用thread模块就会存在主线程提前退出派生线程无法执行完毕,导致下载失败的情况
'''
#这里我不明白原作者为什么要开启一个新线程去下载图片,与直接批量下载图片有什么区别吗,
# 此问题待以后学习更多线程相关的知识后再分析
try:
    threa_download = threading.Thread(target=download_picture,args=(pic_list,))
    threa_download.setDaemon(False)
    threa_download.start()
except:
    print('Error: unable to start thread')


猜你喜欢

转载自blog.csdn.net/blackeagleoht/article/details/83348680