Combat réel | accédez à 36 000 commentaires dans la vallée du ver du Yunnan en python et faites des statistiques et des analyses de visualisation des données pour un look agréable!

Appelez - moi frère. 2022-01-15 03:56:10 阅读数:214

combat el acc dez commentaires

Bonjour tout le monde,C'est moi..

Récemment, la série Ghost blowing Light《Yunnan Worm Valley》En ligne.,Comme une série de lampes fantômes,Entreprendre la partie supérieure《Grotte de Longling》Contenu,Et c'est l'original du triangle de fer,L'appel direct des internautes est très beau!

Aujourd'hui,On va utiliserPython.Pour accéder aux commentaires de tous les épisodes actuels(Avec Trailer),Et faire des statistiques de données et des analyses de visualisation,Suivez les internautes pour voir la pièce!

Cet article détaillera les rampes et la visualisation du traitement des données,Enseigner et s'amuser!

Retour en arrière - plan 210905 Recevoir Code+Données

Table des matières:

1. Analyse des pages Web

Tous les commentaires de Tencent Video(Après tout, seule.)

Ouvre.《Yunnan Worm Valley》Lire la page,F12Entrée dansMode développeur,On glisse et on clique"Voir plus de commentaires",L'adresse réelle de la demande de commentaires peut être trouvée.

Mode développeur

Nous recherchons plusieurs adresses d'interface de commentaires pour une analyse comparative,Trouver la loi

https://video.coral.qq.com/varticle/7313247714/comment/v2?callback=_varticle7313247714commentv2&orinum=10&oriorder=o&pageflag=1&cursor=6838089132036599025&scorecursor=0&orirepnum=2&reporder=o&reppageflag=1&source=132&_=1630752996851
https://video.coral.qq.com/varticle/7313247714/comment/v2?callback=_varticle7313247714commentv2&orinum=100&oriorder=o&pageflag=1&cursor=6838127093335586287&scorecursor=0&orirepnum=2&reporder=o&reppageflag=1&source=132&_=1630752996850
https://video.coral.qq.com/varticle/7313258351/comment/v2?callback=_varticle7313258351commentv2&orinum=10&oriorder=o&pageflag=1&cursor=6838101562707822837&scorecursor=0&orirepnum=2&reporder=o&reppageflag=1&source=132&_=1630753165406

Enfin,Nous avons constaté que cette adresse peut être simplifiée comme suit

url = f'https://video.coral.qq.com/varticle/{
comment_id}/comment/v2?'
params = {

'orinum': 30,
'cursor': cursor,
'oriorder': 't'
}

Ces quatre paramètres ont la signification suivante::

  • orinum Est le nombre de commentaires par demande,Par défaut10- Oui.,J'ai essayé de trouver le plus de support30- Oui.,Donc ici je vais définir la valeur à 30
  • cursor Est le commentaire initial de chaque demandeid,La loi du changement peut être réglée à0,La demande suivante utilise le dernier commentaire de la liste des commentaires de la demande précédenteidC'est tout.
  • oriorder Est le tri des commentaires demandés(tDans l'ordre chronologique,Par défaut est l'autre plus chaud)
  • En plus des trois paramètres ci - dessus,Il y en a un autre.comment_id,Chaque épisode en a un.idUtilisé pour recueillir les commentaires correspondants,C'est pourquoi nous devons encore étudier ça.idOù obtenir

Il vient d'être mentionné que nous devons obtenir des commentaires pour chaque épisodeidDonnées,Il se trouve que nous pouvons obtenir des données de page pour chaque épisode demandé.

Ce qui est important ici, c'est que,Nous utilisons directementrequestsLes données demandées pour chaque page d'épisode ne sont pas exactement les mêmes que celles du côté de la page,Mais les données sont disponibles,On peut trouver quelque chose..

Par exemple,,EpisodeIDLa liste est la suivante::

EpisodeIDListe

Commentaires sur l'épisodeidEmplacement:

Commentaires sur l'épisodeid

Et voilà.,On va utiliserreExpression régulière pour l'analyse des données pour obtenir.

2. Processus de reptile

Grâce à l'analyse des pages Web et à nos besoins de collecte,L'ensemble du processus peut être divisé en:

  • Ramper les données de la page de l'épisode
  • Analyser pour obtenir l'épisodeIDEt les critiques d'épisodesID
  • Recueillir tous les commentaires de l'épisode
  • Enregistrer les données localement

2.1. Importer la Bibliothèque requise

import requests
import re
import pandas as pd
import os

2.2. Ramper les données de la page de l'épisode

# Utilisé pour ramper les données de la page d'épisode
def get_html(url):
headers = {

"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
}
r = requests.get(url, headers=headers)
# Correction du désordre
r.encoding = r.apparent_encoding
text = r.text
# Supprimer les données non - Caractères
html = re.sub('\s', '', text)
return html

2.3. Analyser les épisodesIDEt les critiques d'épisodesID

# Dans les séries télévisées, etc.id,Pour grimper à l'épisodeidEt commentairesid
def get_comment_ids(video_id):
# Adresse du Répertoire
url = f'https://v.qq.com/x/cover/{
video_id}.html'
html = get_html(url)
data_list = eval(re.findall(r'"vip_ids":(\[.*?\])', html)[0])
data_df = pd.DataFrame(data_list)
comment_ids = []
for tid in data_df.V:
# Adresse par épisode
url = f'https://v.qq.com/x/cover/{
video_id}/{
tid}.html'
html = get_html(url)
comment_id = eval(re.findall(r'"comment_id":"(\d+)"', html)[0])
comment_ids.append(comment_id)
data_df['comment_id'] = comment_ids
data_df['Episode'] = range(1,len(comment_ids)+1)
return data_df

2.4. Recueillir tous les commentaires de l'épisode

# Obtenir tous les commentaires de l'épisode
def get_comment_content(data_df):
for i, comment_id in enumerate(data_df.comment_id):
i = i+1
# Initial cursor
cursor = 0
num = 0
while True:
url = f'https://video.coral.qq.com/varticle/{
comment_id}/comment/v2?'
params = {

'orinum': 30,
'cursor': cursor,
'oriorder': 't'
}
r = requests.get(url, params=params)
data = r.json()
data = data['data']
if len(data['oriCommList'])==0:
break
# Données des commentaires
data_content = pd.DataFrame(data['oriCommList'])
data_content = data_content[['id', 'targetid', 'parent', 'time', 'userid', 'content', 'up']]
# Commentaires
userinfo = pd.DataFrame(data['userList']).T
userinfo = userinfo[['userid', 'nick', 'head', 'gender', 'hwlevel']].reset_index(drop=True)
# Fusionner les commentaires avec les commentaires
data_content = data_content.merge(userinfo, how='left')
data_content.time = pd.to_datetime(data_content.time, unit='s') + pd.Timedelta(days=8/24)
data_content['Episode'] = i
data_content.id = data_content.id.astype('string')
save_csv(data_content)
# Suivant. cursor
cursor = data['last']
num =num + 1
pages = data['oritotal']//30 + 1
print(f'No{
i}Episode{
num}/{
pages}Les commentaires de page ont été recueillis!')

2.5. Enregistrer les données localement

# Enregistrer les données des commentaires localement
def save_csv(df):
file_name = 'Données des commentaires.csv'
if os.path.exists(file_name):
df.to_csv(file_name, mode='a', header=False,
index=None, encoding='utf_8_sig')
else:
df.to_csv(file_name, index=None, encoding='utf_8_sig')
print('Enregistrement des données terminé!')

3. Statistiques des données et visualisation

Les statistiques de données et les méthodes de visualisation de cette fois peuvent se référer aux tweets précédents《》Et《》Attendez.

3.1. Aperçu des données

Échantillonnage5Regarde ça.

df.sample(5)

Voir les informations sur les données

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 35758 entries, 0 to 35757
Data columns (total 12 columns):
# Column Non-Null Count Dtype 
--- ------ -------------- -----
0 id 35758 non-null int64
1 targetid 35758 non-null int64
2 parent 35758 non-null int64
3 time 35758 non-null object
4 userid 35758 non-null int64
5 content 35735 non-null object
6 up 35758 non-null int64
7 nick 35758 non-null object
8 head 35758 non-null object
9 gender 35758 non-null int64
10 hwlevel 35758 non-null int64
11 Episode 35758 non-null int64
dtypes: int64(8), object(4)
memory usage: 3.3+ MB

Il a fait des commentaires.,On verra si on l'a.

Commentaire de Chee - ko

C'est mon frère.useridPour1296690233,On va vérifier,Je l'ai trouvé.VIPQuelle classe!6NiveauC'est bon.

df.query('userid==1296690233')

headLe champ est un portrait,Voyons si c'est le portrait du frère aîné.

from skimage import io
# Afficher l'image de la tête
img_url = df.query('userid==1296690233')['head'].iloc[0]
image = io.imread(img_url)
io.imshow(image)

C'est ça.,C'est ça.!!

3.2. Nombre de commentaires sur la diversité

Référence du dessin《》,Donc nous sommes iciPandasDessiner une vue avec interaction,Introduction de l'environnement:

import pandas as pd
import pandas_bokeh
pandas_bokeh.output_notebook()
pd.set_option('plotting.backend', 'pandas_bokeh')

Et puis...,Statistiques officielles des données et visualisation début de la présentation

from bokeh.transform import linear_cmap
from bokeh.palettes import Spectral
from bokeh.io import curdoc
# curdoc().theme = 'caliber'
episode_comment_num = df.groupby('Episode')['id'].nunique().to_frame('Nombre de commentaires')
y = episode_comment_num['Nombre de commentaires']
mapper = linear_cmap(field_name='Nombre de commentaires', palette=Spectral[11] ,low=min(y) ,high=max(y))
episode_bar = episode_comment_num.plot_bokeh.bar(
ylabel="Nombre de commentaires",
title="Nombre de commentaires sur la diversité",
color=mapper,
alpha=0.8,
legend=False
)

Nous pouvons voir,Le plus grand nombre de commentaires dans l'épisode 1,Jusqu'à1.7(En milliers de dollars des États - Unis),La moitié des commentaires;Suivi de la7Nombre de commentaires pour l'ensemble,Surtout cette semaine.7Chiha.!

3.3. Nombre de commentaires par date

df['Date'] = pd.to_datetime(df.time).dt.date
date_comment_num = df.groupby('Date')['id'].nunique().to_frame('Nombre de commentaires')
date_comment_num.index = date_comment_num.index.astype('string')
y = date_comment_num['Nombre de commentaires']
mapper = linear_cmap(field_name='Nombre de commentaires', palette=Spectral[11] ,low=min(y) ,high=max(y))
date_bar = date_comment_num.plot_bokeh.bar(
ylabel="Nombre de commentaires",
title="Nombre de commentaires par date",
color=mapper,
alpha=0.8,
legend=False
)

De8Mois30La journée commence,Les membres peuvent le voir le jour de la première diffusion5Set,En tant que membre, j'ai fini de lire.Nous avons découvert que2Plus de commentaires par jour,Parce que chaque semaine1-3Mise à jour, Le nombre total de commentaires est donc plus élevé ces jours - ci.

3.4. Nombre de commentaires

df['Temps'] = pd.to_datetime(df.time).dt.hour
date_comment_num = pd.pivot_table(df,
values='id',
index=['Temps'],
columns=['Date'],
aggfunc='count'
)
time_line = date_comment_num.plot_bokeh(kind="line",
legend="top_left",
title="Nombre de commentaires"
)

Nombre de commentaires

Courbe des commentaires sur le temps de passage,Nous avons découvert que le jour de la première diffusion8Le nombre d'heures de commentaires a atteint le maximum,Après cela, il est plus conforme au comportement de regarder des séries télévisées:À midi、Plus haut la nuit et minuit.

3.5. CommentateurVIPRépartition des grades

vip_comment_num = df.groupby('hwlevel').agg(Nombre d & apos; utilisateurs=('userid','nunique'),
Nombre de commentaires=('id','nunique')
)
vip_comment_num['Nombre de commentaires par habitant'] = round(vip_comment_num['Nombre de commentaires']/vip_comment_num['Nombre d & apos; utilisateurs'],2)
usernum_pie = vip_comment_num.plot_bokeh.pie(
y="Nombre d & apos; utilisateurs",
colormap=Spectral[9],
title="CommentateurVIPRépartition des grades",
)

Je dois dire,CommentateurLa plupart d'entre euxVIPUtilisateurs,Pas étonnant que la vidéo de Tencent ait fait ce qu'on appelleVIPOui.VIP...

C'est différent.VIPLe nombre de commentaires par utilisateur variera - t - il??

y = vip_comment_num['Nombre de commentaires par habitant']
mapper = linear_cmap(field_name='Nombre de commentaires par habitant', palette=Spectral[11] ,low=min(y) ,high=max(y))
vipmean_bar = vip_comment_num.plot_bokeh.bar(
y = 'Nombre de commentaires par habitant',
ylabel="Nombre de commentaires par habitant",
title="C'est différent.VIPNombre de commentaires par utilisateur",
color=mapper,
alpha=0.8,
legend=False
)

Présente essentiellement unVIPPlus le grade est élevé Plus la volonté d'évaluer est élevée!Mais pourquoi??

3.6. Longueur des commentaires

La plupart des internautes qui écrivent des commentaires sont666,Joli vocabulaire.,Comme le frère aîné.Attendre la mise à jourTrois mots,Combien de caractères sont généralement évalués?

import numpy as np
df['Longueur des commentaires'] = df['content'].str.len()
df['Longueur des commentaires'] = df['Longueur des commentaires'].fillna(0).astype('int')
contentlen_hist = df.plot_bokeh.hist(
y='Longueur des commentaires',
ylabel="Nombre de commentaires",
bins=np.linspace(0, 100, 26),
vertical_xlabel=True,
hovertool=False,
title="Histogramme des commentaires",
color='red',
line_color="white",
legend=False,
# normed=100,
)

Regardons quelques commentaires

(df.sort_values(by='Longueur des commentaires',ascending=False)
[['Episode','content','Longueur des commentaires','nick','hwlevel']].head(3)
.style.hide_index()
)

Je dirais,C'est là que le commentaire a été copié.,C'est un génie.?

3.7. Commentaires favorables

.Regardons quelques - uns des plus appréciés

# pd.set_option('display.max_colwidth',1000)
(df.sort_values(by='up',ascending=False)
[['Episode','content','up','nick','hwlevel']].head()
.style.hide_index()
)

Voir la carte Ne te perds pas.!C'est un pédoncule??Super.8000C'est super.~~

3.8. Utilisateurs les plus commentés

user_comment_num = df.groupby('userid').agg(Nombre de commentaires=('id','nunique'),
vipGrade=('hwlevel','max')
).reset_index()
user_comment_num.sort_values(by='Nombre de commentaires',ascending=False).head()
userid Nombre de commentaires vipGrade
640014751 33 5
1368145091 24 1
1214181910 18 3
1305770517 17 2
1015445833 14 5

Évaluation33Article (s),L'utilisateur est très bon aussi.!!Voyons ce qu'il a dit.:

df.query('userid==640014751')[['nick','Episode','time','content']].sort_values(by='time')

C'est un peu ennuyeux.,C'est une bonne nouvelle.!!Regardons le deuxième plus grand nombre de petits partenaires!

df.query('userid==1368145091')[['nick','Episode','time','content']].sort_values(by='time')

Je dois dire,C'est normal...Mais,Je me sens un peu bavard.,Ha Ha!!

C'est quoi, ces deux - là?,Regarde ça avec intérêt.:

from skimage import io
# Afficher l'image de la tête
img_url = df.query('userid==640014751')['head'].iloc[0]
image = io.imread(img_url)
io.imshow(image)

Le plus grand commentaire

from skimage import io
# Afficher l'image de la tête
img_url = df.query('userid==1368145091')['head'].iloc[0]
image = io.imread(img_url)
io.imshow(image)

Commentaire n° 2

Toux,Je ne ferai pas d'évaluation.,Après tout, ma tête et mon surnom sont très bons.…

3.9. Commentaire Cloud

Référence à cette section《》,Nous allons commencer par le nuage de mots entiers et les parties du nuage de mots principaux

Voyons d'abord combien de fois nos trois personnages principaux ont parlé

df.fillna('',inplace=True)
hu = ['Lao Hu.','Merde!','Pan Yueming','Hu','Pan!']
yang = ['Zhang Yuqi','Shirley','Yang.']
wang = ['Jiang Chao','Le gros']
df_hu = df[df['content'].str.contains('|'.join(hu))]
df_yang = df[df['content'].str.contains('|'.join(yang))]
df_wang = df[df['content'].str.contains('|'.join(wang))]
df_star = pd.DataFrame({
'Rôle':['Merde!','ShirleyYang.','Chubby Wang.'],
'Poids':[len(df_hu),len(df_yang),len(df_wang)]
})
y = df_star['Poids']
mapper = linear_cmap(field_name='Poids', palette=Spectral[11] ,low=min(y) ,high=max(y))
df_star_bar = df_star.plot_bokeh.bar(
x = 'Rôle',
y = 'Poids',
ylabel="Poids de référence",
title="Poids de référence du rôle principal",
color=mapper,
alpha=0.8,
legend=False
)

Le gros Wang sourit.,Je dois dire que c'est très fréquent.!!!

Nuage de mots entiers

Nuage de mots entiers

Hu Ba word cloud

Merde!

ShirleyYang ciyun

Zhang Yuqi

Wang chuzi ci Yun

Chubby Wang.

Word cloud Core Code

import os
import stylecloud
from PIL import Image
import jieba
import jieba.analyse
import pandas as pd
from wordcloud import STOPWORDS
def ciYun(data,addWords,stopWords):
print('Dessin en cours...')
comment_data = data
for addWord in addWords:
jieba.add_word(addWord)
comment_after_split = jieba.cut(str(comment_data), cut_all=False)
words = ' '.join(comment_after_split)
# Mots désactivés par word cloud 
stopwords = STOPWORDS.copy()
for stopWord in stopWords:
stopwords.add(stopWord)
# Juste le code ci - dessous.,Vous pouvez obtenir des paramètres qui répondent aux exigences de type
stylecloud.gen_stylecloud(
text=words,
size = 800,
palette='tableau.BlueRed_6', # Définir le schéma de couleurs
icon_name='fas fa-mountain',# paper-plane mountain thumbs-up male fa-cloud
custom_stopwords = stopwords,
font_path='FZZJ-YGYTKJW.TTF'
# bg = bg, 
# font_path=font_path, # Carte des nuages Police(Le chinois doit être réglé à la police chinoise disponible sur cet ordinateur)
)
print('Mot Cloud généré~')
pic_path = os.getcwd()
print(f'Le fichier word cloud Map a été enregistré dans {
pic_path}')
data = df.content.to_list()
addWords = ['M. PAN.','Yunnan Worm Valley','Degré de réduction',
'Lao Hu.','Merde!','Pan Yueming',
'Zhang Yuqi','Shirley','ShirleyYang.','Officier Yang',
'Chubby Wang.','Le gros']
# Ajouter un mot de désactivation
stoptxt = pd.read_table(r'stop.txt',encoding='utf-8',header=None)
stoptxt.drop_duplicates(inplace=True)
stopWords = stoptxt[0].to_list()
words = ['Dis - le.','Année','VIP','C'est vrai.','C'est','- Non.','Merde!','Comme si']
stopWords.extend(words)
# Exécution~
ciYun(data,addWords,stopWords)

C'est tout ce qui précède,Si vous êtes intéressé,C'est bien.+Je regarde,Retour en arrière - plan 210905 Code de réception+Données!

版权声明:本文为[Appelez - moi frère.]所创,转载请带上原文链接,感谢。 https://pythonmana.com/2022/01/202201080611484662.html