python爬取豆瓣短评(web端和app端)+jieba分词+collections词频统计+wordcloud词云生成

整理整理之前的东西,当时有个需求要爬豆瓣短评,当时没想太多,打开Chrome,登录豆瓣,冲!!!


c192b36ff917a84124ea6e3296e6c80.png

整一个《龙猫》 看看,豆瓣短评就在下面,点击全部


6ff1932bde627d3a3346ed061030867.png

fd63a0d50185c5eb789cbbc1dbbd488.png

f12 看了一眼,xhr里没有,那肯定是在页面上了,果不其然,嘻嘻

43d28562210df1f1ff20689d6d70d78.png
2df8d7baa0a7b2a177578ace7160d94.png

data-cid 是这个评论的id,是唯一的,我们爬取评论只把 这个标签下的文本取下来就行了。
通过研究,登录之后能抓的多一点,自己的账号先登录,把cookie拿下来。

fef89ad8e70692d4beed88ac66cbe6c.png

为了尽可能模拟浏览器,我用了个代理,蘑菇代理http://www.moguproxy.com/(不是打广告 - -.)

# coding : utf8

import urllib
import urllib.request
import time
import random
from bs4 import BeautifulSoup


def get_html(url,proxy):


    user_agents = [
      #(这里可以多填几个,你萌自己找8)
       'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36'
    ]

    headers = {
        "User-Agent": str(random.choice(user_agents)),
        "Cookie": "chrome f12里面拿到的cookie",
        'Referer': 'movie.douban.com',
        'Connection': 'keep-alive'
    }
    http_proxy = urllib.request.ProxyHandler(proxy)
    opener = urllib.request.build_opener(http_proxy)
    req=urllib.request.Request(url,headers=headers)
    req = opener.open(req)
    html = req.read().decode('utf-8')
    comment_soup = BeautifulSoup(html, 'html.parser')
    comments = comment_soup.findAll('span', 'short')
    page_comment = []
    for comment in comments:
        page_comment.append(comment.getText() + '\n')
    return page_comment

def get_proxy():

    for i in range(20):
        print("get proxy try time:", i + 1)
        proxy_url = urllib.request.urlopen(
            "http://piping.mogumiao.com/proxy/api/get_ip_al?appKey=蘑菇代理的订单号&count=1&expiryDate=0&format=2&newLine=1",
        ).read()
        proxy_origin = {"http": "http://%s" % proxy_url}
        headers = {
            'Accept - Encoding': 'gzip',
            'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}
        try:
            proxy = urllib.request.ProxyHandler(proxy_origin)
            opener = urllib.request.build_opener(proxy)
            #因为不是所有代理都是有效可用的,拿到代理之后先去试一下,用baidu当小白鼠,可以正常访问之后,就使用这个代理,不好用就换下一个,重试20次
            req = urllib.request.Request("https://www.baidu.com/", headers=headers)
            req = opener.open(req)
            time.sleep(0.5)
            return proxy_origin
        except:
            continue
    return None
if __name__ == "__main__":

    file = open('/Users/zhangxiaoke/Desktop/comment_test.rtf', 'a', encoding='utf-8')
    j = 0
    for page in range(25):
        proxy = get_proxy()
        url = 'https://movie.douban.com/subject/1291560/comments?start=' + str(20 * page) + '&limit=20&sort=new_score&status=P'
        print('爬取url :' + url + '\n')
        for i in get_html(url,proxy):
            file.write(i)
            print(j+1, i)
            j += 1
        time.sleep(10)
    print('end')

点击运行 :


image.png

文本里面有emogi,这个没处理,python里面好像有个 emoji包,处理表情的,有需要的pip3 install 一下,然后在文本那里处理一下

无情爬了半天,发现豆瓣只展示500条,这还是在登录的情况下,我原本以为只是页面展示500调,结果改接口参数,到500条之后就返回空了 - -
然而第二天早上醒来


image.png

忘了件事,就算我用代理 - -,就算用多个User_agent,那cookie还是我账号的 - -。。。一个账号同时在多个ip多个浏览器访问douban,douban没惯着我,直接给我封了 - -。。

这咋整,去app看看还有没有可能。

注意 :

以上代码不用代理,用自己电脑的ip和自己的cookie,也能抓,把代理那一步去掉就行。

在mac上用Charles链接iphone抓包,就是抓不到,就奇了怪了 。。 因为mac的fiddler非常难用,不是正经的开发版本,卡的1b。转战windows。这里使用 Fiddler和网易mumu模拟器。(不会Charles和fiddler的可以去看一下啊)
下载fiddler : https://pc.qq.com/detail/10/detail_3330.html
下载mumu模拟器 : http://mumu.163.com/baidu/
网上这位大佬写的非常详细,怎么使用fiddler抓包模拟器:https://blog.csdn.net/lengdaochuqiao/article/details/88170522
之后记得下载证书,要不然把代理填上之后,无法上网 - -

c9dcb7cfa20b497b6edab0ef05742f4.png

mumu模拟器下载完豆瓣之后打开,咱看看天空之城:
image.png

image.png

image.png

找到啦 ! (fiddler那个443没来得及处理)

https://frodo.douban.com/api/v2/movie/1291583/interests?count=30&status=done&order_by=hot&os_rom=android&apikey=0dad551ec0f84ed02907ff5c42e8ec70&channel=douban&udid=c1e35b2e04e6fadee7de08bb7c287dd46809a84b&_sig=EDicFbQBh20lHnBG2AKZr%2FUD8TM%3D&_ts=1587272260

这个链接可以改成下面这样子,就可以分页抓了,在模拟器里往下划,就会出现这个链接了,评论接口里有2个参数,可以控制返回 ’热门‘ 还是 ’最新‘ ’看过‘ 还是 ’没看过‘


image.png
#start 开始条数 count 总条数 status = done 看过 status = mark 想看 order_by = hot热评 order_by = latest最新
https://frodo.douban.com/api/v2/movie/1291583/interests?start=0&count=75011&status=done&order_by=latest&os_rom=android&apikey=0dad551ec0f84ed02907ff5c42e8ec70&channel=douban&udid=c1e35b2e04e6fadee7de08bb7c287dd46809a84b&_sig=NY106LqdT%2BysFZgXAAnvDpWuejg%3D&_ts=1587264829

注意 没有User_agent不行

image.png

只能展示 500 条,我们把start换成501试验一把:


image.png

就不显示了,这个我在本地爬了几回,然后也给我封了,可以在postman的setting里面设置一个代理,就可以继续了,


image.png
上代码了
# coding : utf8

import urllib
import urllib.request
import time
import json


def get_json(url,proxy):

    headers = {
        "User-Agent": 'api-client/1 com.douban.frodo/6.33.1(183) Android/23 product/cancro vendor/Netease model/MuMu rom/android network/wifi platform/AndroidPad',
        'Referer': 'frodo.douban.com',
        'Connection': 'keep-alive'
    }

    http_proxy = urllib.request.ProxyHandler(proxy)
    opener = urllib.request.build_opener(http_proxy)
    req = urllib.request.Request(url,headers=headers)
    req = opener.open(req)
    content = req.read().decode('utf-8')
    jsonobj = json.loads(content)

    comment_list = jsonobj['interests']
    page_comments = []
    for comment in comment_list:
        page_comments.append(comment['comment'].strip("\n") + '\n')
    return page_comments


这里我也用了代理,如果没有代理使用本机的话,可以不用,一样可以抓,但是没测试能抓多少回,我猜可能抓个10几次就403了  - - ,买了代理后把链接换成 prox_url里面就可以,或者用别人的机器和端口 ,proxy_url = {'http':u'192.xxx.xx.xx:8080'} 这样也可以


def get_proxy():

    for i in range(20):
        print("get proxy try time:", i + 1)
        proxy_url = urllib.request.urlopen(
            "http://piping.mogumiao.com/proxy/api/get_ip_al?appKey=蘑菇代理apikey&count=1&expiryDate=0&format=2&newLine=1",
        ).read()
        proxy_origin = {"http": "http://%s" % proxy_url}
        headers = {
            'Accept - Encoding': 'gzip',
            'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}
        try:
            proxy = urllib.request.ProxyHandler(proxy_origin)
            opener = urllib.request.build_opener(proxy)
            req = urllib.request.Request("https://www.baidu.com/", headers=headers)
            #等待5秒,没有响应就跳过
            req = opener.open(req,timeout=5)
            time.sleep(0.5)
            return proxy_origin
        except:
            continue
    return None




if __name__ == "__main__":

    # a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容 
    将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。   
    file= open('/Users/zhangxiaoke/Desktop/天空之城.txt', 'a', encoding='utf-8')
    j = 0
    for page in range(10):
        proxy = get_proxy()
        # status : done 看过 mark 想看
        # order_by hot 热评  latest 最新
        #天空之城
        url = 'https://frodo.douban.com/api/v2/movie/1291583/interests?start='+str(50 * page)+'&count=75011&status=done&order_by=latest&os_rom=android&apikey=0dad551ec0f84ed02907ff5c42e8ec70&channel=douban&udid=c1e35b2e04e6fadee7de08bb7c287dd46809a84b&_sig=NY106LqdT%2BysFZgXAAnvDpWuejg%3D&_ts=1587264829'
        print('爬取'+url + '\n')

        for i in get_json(url,proxy):
            file.write(i)
            print(j+1, i)
            j += 1
        time.sleep(10)
    print('end')
![image.png](https://upload-images.jianshu.io/upload_images/18395572-ccb572562ef4ca42.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![image.png](https://upload-images.jianshu.io/upload_images/18395572-faa34b5fba14c24e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

相比在web端抓取呢,app端不用cookie,但是最好使用代理,app端解析json,web端解析html。

生成词云

使用 jieba分词 colection统计次频率 把高频词用wordcloud做词云


from wordcloud import WordCloud
import matplotlib.pyplot as p
import jieba
import jieba.analyse
import collections
import numpy
import re
import numpy as np

def wordCloudImg(path) :

    f = open(path,'r',encoding='UTF-8')

    # 文本预处理
    pattern = re.compile(u'\t|\n|\.|-|:|;|\)|\(|\?|"')  # 定义正则表达式匹配模式
    string_data = re.sub(pattern, '', f.read())
    f.close()
    # 将符合模式的字符去除
    jieba.analyse.set_stop_words("/Users/zhangxiaoke/Desktop/stopwords.txt")

    stop_list = [u'的', u',',u'和', u'是', u'随着', u'对于', u'对',u'等',u'能',u'都',u'。',u' ',u'、',u'中',u'在',u'了',
                 u'通常',u'如果',u'我们',u'需要',u'就是',u'他们',u'那么',u'有',u'一个',u'一部',u'这部',u'没有',u'还是',u'时候',u'看到',u'还有',u'觉得']
    use_workd = ['久石让']
    for uword in use_workd:
        jieba.add_word(uword)
    cut_text = jieba.cut(string_data,cut_all=False,HMM=True)

    object_list = []

    for word in cut_text:
        if word not in stop_list:
            if len(word) == 1:
                continue
            else:
                object_list.append(word)

    word_counts = collections.Counter(object_list)
    word_count_top = word_counts.most_common(150)

    new_file = open('/Users/zhangxiaoke/Desktop/final_word.txt', 'w', encoding='utf-8')

    for wordd in word_count_top:
        print(wordd[0],"    ",wordd[1]*151)
        new_file.write(wordd[0])

    new_file.close()

    final_file = open('/Users/zhangxiaoke/Desktop/final_word.txt', 'r', encoding='utf-8')
    cut_text2 = jieba.cut(final_file.read(),cut_all=False,HMM=True)
    str = ' '.join(cut_text2)

    # wordcloud = WordCloud(
    #     font_path="/System/Library/Fonts/Supplemental/Songti.ttc",
    #     background_color="white",
    #     width=1380,
    #     height=880).generate(str)

    x, y = np.ogrid[:600, :600]
    mask = (x - 300) ** 2 + (y - 300) ** 2 > 230 ** 2
    mask = 255 * mask.astype(int)

    wordcloud = WordCloud(
        font_path="/System/Library/Fonts/Supplemental/Songti.ttc",
        background_color="white",
        mask=mask).generate(str)

    #图像显示 - interplotation:默认"None",可用字符串类型命令设定
    p.imshow(wordcloud)
    p.axis("off")
    p.show()

if __name__ == "__main__":
    path = '/Users/zhangxiaoke/Desktop/龙猫.txt'
    wordCloudImg(path)


效果图 :


image.png

你可能感兴趣的:(python爬取豆瓣短评(web端和app端)+jieba分词+collections词频统计+wordcloud词云生成)