当前位置:   article > 正文

python爬取豆瓣影评_python爬虫绘制影评图

python爬虫绘制影评图
爬取准备

所需第三方库:requests,re,time,pymongo,random
爬取网站需联网

思路分析

评论第一页网址: https://movie.douban.com/subject/26266893/reviews?start=0

评论第二页网址: https://movie.douban.com/subject/26266893/reviews?start=20

由此分析,每页评论有20个,而网址的改变也只是在最后,网址的前半部分https://movie.douban.com/subject/26266893/reviews?start=都一样,而后面变的参数代表了第多少条评论,所以要爬取所以影评的动态网址的格式为:https://movie.douban.com/subject/26266893/reviews?start=加上20的倍数。

#前半部分固定的内容
url = r'https://movie.douban.com/subject/26266893/reviews?start='
page=0#表示评论页数
k = 0#表示评论条数
while page<1073:#检查网页可知流浪地球共有1073页影评
    urls = url+str(k)#获得一个完整的网址
    page = page+1
    k = k+20#每一页有20条评论
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

动态网页网址已经分析清楚后就可以直接用requests库抓取网页代码

import requests
while page<1073:
    urls = url+str(k)#拼接成完整的网址
    header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0'}#根据HTTP协议,设置请求头
    response = requests.get(urls, headers=header)#获取源代码
    print(response.text)#打印网页源代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

影评格式:
影评格式
网页中需要提取的目标字段包括作者,评价星级,发布时间及影评内容,所以我采用的是正则匹配来获取

#将提取目标字段的功能封装成函数
import re
def re_select(string):
    # 取出作者字段
    pat_author = r'class="name">(.*?)</a>'
    re_au = re.compile(pat_author, re.S)
    auList = re_au.findall(string)#获取目标文档中的所有符合条件的字段
    # 取出评价等级字段
    pat_level = r'main-title-rating" title="(.*?)"></span>'
    re_level = re.compile(pat_level, re.S)
    levelList = re_level.findall(string)
    # 取出影评内容
    pat_story = r'<div class="short-content">(.*?) &nbsp;'
    re_story = re.compile(pat_story, re.S)
    storyList = re_story.findall(string)
    for i in range(len(storyList)):#将获取的字段进行格式调整
        storyList[i] = storyList[i].strip()#去掉字段中的空白字符
        storyList[i] = re.sub(r"[a-z\s\"\<\>\/\=\-]", "", storyList[i])#删除多余的字符
    # 取出评价时间
    pat_time = r'class="main-meta">(.*?)</span>'
    re_time = re.compile(pat_time, re.S)
    timeList = re_time.findall(string)
    #返回所有的目标字段列表
    return auList,levelList,storyList,timeList
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

获取数据后可以选择保存为文件格式,也可以保存到本地数据库中。我选择的是保存到本地mongodb数据库中,也将其封装为函数:

#连接数据库
def linkmongo():
    # 连接mongodb数据库
    myclient = pymongo.MongoClient("mongodb://localhost:27017")
    # 查看数据库名
    dblist = myclient.list_database_names()
    # 指定mydb数据库
    mydb = myclient.mydb
    # 指定mydb数据库里豆瓣集合
    collection = mydb.douban
    # 返回游标
    return collection
#调用函数,只调用一次,不要加在后面的循环中
collection = linkmongo()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

最后就是把所有功能整合就行了,但是还需要提高代码健壮性,本应该加一个异常处理,但是不想搞了,所有直接将出现异常的数据不要,直接请求下一页,总共几万条数据,少几条也没啥事,就这样吧!!!
总代码:

#author  mjz
#data     2019/12/4/16:19
import requests
import re
import time
import pymongo
import random

url = r'https://movie.douban.com/subject/26266893/reviews?start='
#定义一个内核列表
u_a = [ 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0',
        'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10',
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0']

def linkmongo():
    # 连接mongodb数据库
    myclient = pymongo.MongoClient("mongodb://localhost:27017")
    # 查看数据库名
    dblist = myclient.list_database_names()
    # 指定mydb数据库
    mydb = myclient.mydb
    # 指定mydb数据库里user集合
    collection = mydb.douban
    return collection
collection = linkmongo()
def re_select(string):
    # 取出作者字段
    pat_author = r'class="name">(.*?)</a>'
    re_au = re.compile(pat_author, re.S)
    auList = re_au.findall(string)
    # 取出评价等级字段
    pat_level = r'main-title-rating" title="(.*?)"></span>'
    re_level = re.compile(pat_level, re.S)
    levelList = re_level.findall(string)
    # 取出影评内容
    pat_story = r'<div class="short-content">(.*?) &nbsp;'
    re_story = re.compile(pat_story, re.S)
    storyList = re_story.findall(string)
    for i in range(len(storyList)):
        storyList[i] = storyList[i].strip()
        storyList[i] = re.sub(r"[a-z\s\"\<\>\/\=\-]", "", storyList[i])
    # 取出评价时间
    pat_time = r'class="main-meta">(.*?)</span>'
    re_time = re.compile(pat_time, re.S)
    timeList = re_time.findall(string)
    return auList,levelList,storyList,timeList

page=0
k = 0
while page<1073:
    urls = url+str(k)
    user = random.randint(0, 2)
    header = {'User-Agent': u_a[user]}
    response = requests.get(urls, headers=header)
    page = page + 1
    #防止短时间内请求次数过多被网站封IP,所有爬一个页面后休息5秒,爬100个后休息一分钟
    if page % 100 == 0:
        time.sleep(60)
    else:
        time.sleep(5)
    k = k + 20
    if response.status_code == 200:
        print("成功爬取评论第%d页......" % page)
        auList, levelList, storyList, timeList = re_select(response.text)
        length = len(len(auList))
        #如果提取的页面信息有缺失,则不要当前页面的信息,直接跳转到下一页面继续爬取
        if(len(levelList)!=length or len(levelList)!=length or len(timeList)!=length):
            continue
        for i in range(len(auList)):
            di = {'作者': auList[i], '评级': levelList[i], '评论': storyList[i], '评论时间': timeList[i]}
            collection.insert(di)
    else:
        print("爬取失败.......")


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

因为这次用的是单线程,要爬完得很久,没有等到运行结束,但是也运行了两百多个页面,代码还是稳定的,应该没问题的。。。

运行截图:

在这里插入图片描述所有的东西就是这样了,算是敏捷开发吧,只实现了功能,要修改也有许多地方可以修改,就当开源吧,希望有人能帮我完善哈。。。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/686997
推荐阅读
相关标签
  

闽ICP备14008679号