私は最近、上記のデータをクロールし、データ分析と視覚化を行い、最終的なワードクラウドマップを作成しました。
このクロールと過去は非常に異なっている:Webページがajax動的ロード、分析のWebページの構築と長い時間を費やしただけでなく、崔清才お兄ちゃんのビデオを見るためにB駅に行くために、全体的にまだ難易度を増加させます。
クローラーは本当に簡単ではありません学べば学ぶほど難しくなります!ハハハ。
週末の食べ物
今週の料理はこちら!最高ですプロダクションの特徴をまとめました:
- ニンニクをもっと食べてください。
- 赤ピーマンや角切りにしたニンジンを入れると彩りがよくなります。
- 最終的に煮詰まったら、水は少なめに。
クロールコンテンツ
- 問題名
- はじめに概要
- 石工カウント石工
- ウォッチ
- コメント
データ
記事は全部あるのですが、なぜかクロールされるのはいつも527=58*9+5記事だけです。クロールの最後のページには、いつも以下の記事しかありません。
ウェブページのコード構造が同じなので、非常に意味不明から抜け出せません一応、この方法で!
実際にクロールされたデータは棒グラフだけです:
ページ構成
ajax
"AJAXは、ページ全体を再読み込みすることなく、ウェブページの一部を更新できる技術です。
例えば、このページ開き、まず動かずに右側のスクロールバーの長さを観察し、スクロールバーを最後まで引くと、スクロールバーが短くなる、つまりページが長くなる、つまりこの時にデータの一部が読み出されます。この処理は、ajax技術に基づいた動的な読み込みです。スクロールバーを引くと、ページ上のデータはより多くなりますが、URLは常に変更されません。
"
ウェブ更新
<li></li>例えば、このウェブページソースコードでは、右側のカラムのスクロールバーが静止しているとき、9つの記事、すなわち9つのタグだけが
これで、スクロールバーが下にスライドされると、liタグが自動的に更新されます。
ウェブページの法律
ajaxでロードされたページについては、Right-Click-Inspection-Networks-XHRを参照してください:
ヘッダ経由でURLアドレスを取得します:
これは、クロール全体のURLアドレスを見つけ、ネットワーク全体からのデータのクロールを可能にします。
クロールデータ
インポートライブラリ
import re
import requests
import pandas as pd
import csv
import jieba
import numpy as np
import matplotlib.pyplot as plt
#
import random
import plotly as py
import plotly_express as px
import plotly.graph_objects as go
import dash
import dash_core_components as dcc
import dash_html_components as html
# すべての列を表示する
# pd.set_option('display.max_columns', None)
# すべての行を表示する
# pd.set_option('display.max_rows', None)
# 値の表示長さを100に設定する、デフォルトは50である
# pd.set_option('max_colwidth',100)
ウェブコンテンツの取得
リクエストライブラリによるウェブコンテンツの取得
url = "https://..//?_=_&;=1"
headers = {"User-Agent": "実際のリクエストヘッダ "}
response = requests.get(url=url,headers=headers) # 応答を取得する
res = response.content.decode('utf-8', 'ignore') # ソースコードを取得する
result.append(res)
単一のフィールドをクロール
例えば名前:
その他のフィールドの正規表現は以下の通り:
abstract = re.findall('<p class="abstract">\s*(.*?)
\s*</p>', result, re.S)
watch = re.findall('class="iconfont ic-list-read"></i>(.*?)\s</a>',result, re.S) # \s空白文字に一致する;\S空白以外の文字にマッチする
comment = re.findall('class="iconfont ic-list-comments"></i>(.*?)\s</a>',result, re.S)
like = re.findall('class="iconfont ic-list-like"></i>(.*?)</span>',result, re.S)
time = re.findall('lass="time" data-shared-at=(.*?)></span>',result, re.S)
ページあたりの各フィールドの数が9であることを確認するのがよいでしょう:
時間は、年、月、日ではなく、特定の時間だけにクロールします。
ネットワーク全体をクロール
「URLアドレスとリクエストヘッダを変更する必要があります。
# from multiprocessing import Pool
import re
import requests
import pandas as pd
import csv
import jieba
import numpy as np
import matplotlib.pyplot as plt
# !!!データに書き込まれた属性フィールドが重複しないようにするためである。
# ファイルを書く
with open(".csv", "a", encoding="utf-8") as f: # 書き込みモードを "a "に変更:追記モードを示す
writer =csv.DictWriter(f,fieldnames=["name","abstract","read","comment","like","time"])
writer.writeheader()
# urlアドレスとリクエストヘッダを実際のコンテンツに置き換える必要がある
for i in range(1,60): # 59ページのデータをクロールする
url = "https://..//?_&;ge={}".(i)
headers = {"User-Agent": "実際のリクエストヘッダ"}
response = requests.get(url=url,headers=headers) # 応答を得る
res = response.content.decode('utf-8', 'ignore')
name_list = re.findall('class="title" target="_blank".*?>(.*?)</a>',res, re.S)
#
:改行する;\s*:ブランクは何回でも;\.\.\.マッチ3...
abstract_list = re.findall('<p class="abstract">\s*(.*?)
\s*</p>', res, re.S)
# 一致する数字だけを書く:{1}1回の一致を示す;{1,}少なくとも1つの一致を示す
# masonry_list = re.findall(r'class="iconfont ic-paid1"></i>\s(\d{1,}.\d{1,}).*?</span>',res, re.S)
read_list = re.findall('class="iconfont ic-list-read"></i>(.*?)\s</a>',res, re.S) # \s空白文字に一致する;\S空白以外の文字にマッチする
comment_list = re.findall('class="iconfont ic-list-comments"></i>(.*?)\s</a>',res, re.S)
like_list = re.findall('class="iconfont ic-list-like"></i>(.*?)</span>',res, re.S)
time_list = re.findall('lass="time" data-shared-at=".*?T(.*?)\+.*?></span>',res, re.S)
result_list = []
for j in range(len(name_list)):
result = {
"name": name_list[j],
"abstract": abstract_list[j],
# "masonry": masonry_list[j],
"read": read_list[j],
"comment": comment_list[j],
"like": like_list[j],
"time": time_list[j]
}
result_list.append(result)
writer.writerows(result_list)
データ処理
完全なネットワークデータ
ネットワーク全体のデータは上記のコードで得られます:
フィールド情報
time
ソート
最初に時間フィールドでソート
df_sort = df.sort_values("time")
print(df_sort.dtypes)
属性の変更
解決策は、時間フィールドのオブジェクトデータ型を時間に関連するものに変更することです。
後でわかったのですが、時間フィールドは処理しなくても問題なく機能するようです。
散布図
fig = px.scatter(df_sort,x="name",y="time",color="like",height=900,width=1350)
app = dash.Dash()
app.layout = html.Div([
dcc.Graph(figure=fig)
])
app.run_server()
timeマーカー処理
処理ルール
出版までの時間を人為的に4段階に分け、異なる値で表現:
- Sqlzoo
- ゼロ - 午前8時:1
- 午前8時から午後2時まで:2
- 午後2時-午後8時:3
フラグフィールドを追加
上記の情報をマークする新しいフィールドフラグを追加します:
for i in range(len(df_sort)):
if "" <= df_sort.loc[i,"time"] < "":
df_sort.loc[i,"flag"] = 1
elif "" <= df_sort.loc[i,"time"] < "":
df_sort.loc[i,"flag"]= 2
elif "" <= df_sort.loc[i,"time"] < "":
df_sort.loc[i,"flag"] = 3
else:
df_sort.loc[i,"flag"] = 4
fig = px.scatter(df_sort,x="flag",y="time",color="flag",height=800,width=1350)
app = dash.Dash()
app.layout = html.Div([
dcc.Graph(figure=fig)
])
app.run_server()
図面
結論
上のグラフからわかるように、第4ステージ内に記事が掲載される確率が高く、ほとんどの記事が夕方に掲載されることを示唆しています。
read
データ情報
図面
#
# 色のランダム生成:# # プラス6桁の構成
def random_color_generator(number_of_colors):
color = ["#"+''.join([random.choice('ABCDEF') for j in range(6)])
for i in range(number_of_colors)]
return color
text = read.values
trace = go.Bar(
x = read.index,
y = read.values,
text = text,
marker = dict(
color = random_color_generator(232),
line = dict(color='rgb(8, )', # 列の周囲の線の色と幅
width = 1.5)
),
opacity = 0.5 # 透明度の設定
)
# データ部分:リストの形式でなければならない
data = [trace]
# レイアウト設定
layout = go.Layout(
title = 'Information of read', # 全体の図のタイトル
margin = dict(
l = 100 # 左の距離
),
xaxis = dict(
title = 'Number of reading' # 2軸のタイトル
),
yaxis = dict(
title = 'Count of the number of reading'
),
width = 70000, # figure
height = 800
)
fig = go.Figure(data=data, layout=layout)
fig.update_traces(textposition="outside") # 稼働率、つまりY軸の値をそれぞれ表示する
fig.show()
結果
右にスワイプした結果のスクリーンショットの一部
別の描き方:
px.bar(x=read.index,y=read.values,color=read.index,range_color=[0],height=800,width=30000)
図面
結論
上の円グラフに見られるように、
like
データ
図面
#
# 色のランダム生成# # プラス6桁の構成
def random_color_generator(number_of_colors):
color = ["#"+''.join([random.choice('ABCDEF') for j in range(6)])
for i in range(number_of_colors)]
return color
trace = go.Bar(
x = like_number.index,
y = like_number.values,
text = text,
marker = dict(
color = random_color_generator(100),
line = dict(color='rgb(8, )', # 列の境界線の色と幅
width = 1.5)
),
opacity = 0.7 # 透明度の設定
)
# データ部分:リストの形式でなければならない
data = [trace]
# レイアウト設定
layout = go.Layout(
title = 'Information of like', # 全体の図のタイトル
margin = dict(
l = 100 # 左の距離
),
xaxis = dict(
title = 'Number of like' # 2軸のタイトル
),
yaxis = dict(
title = 'Count of like'
),
width = 900, # figure
height = 500
)
fig = go.Figure(data=data, layout=layout)
fig.update_traces(textposition="outside") # 稼働率、つまりY軸の値をそれぞれ表示する
fig.show()
結論
語彙分析とワードクラウドマッピング
- 午後8時-12時:4
主にjiebaセグメンテーションとwordcloudを使用してワードクラウドを作成しています。
Jieba語彙分析
リストを生成
分詞の実装
# 2-スプリットフレーズを実装する
for i in range(len(name_list)):
seg_list = jieba.cut(name_list[i].strip(), cut_all=False) # seg_listただのジェネレータジェネレータ:<class 'generator'>
print(("Default Mode: " + "/ ".join(seg_list))) # リストメソッドで展開する
セグメンテーション結果のリスト化
# 3-分詞のすべての結果をリストに入れ、簡単にフォローアップ処理する
jieba_name = []
for i in range(len(name_list)):
seg_list = jieba.cut(name_list[i].strip(), cut_all=False) # seg_listただのジェネレータジェネレータ:<class 'generator'>
for str in list(seg_list): # リストへ(seg_list)各要素を追加する
jieba_name.append(str)
jieba_name
jieba使用概要
- 保留中の文章をリストに
- リストの各センテンスを分割します。
- 上記のステップで単語を分割した結果を別のリストに入れ、その後の処理を容易にします。
Wordcloud
図面
from wordcloud import WordCloud
import matplotlib.pyplot as plt
text = " ".join(i for i in jieba_name) # 保留中の文字列
# 最初にSimHeiをダウンロードする.ttfフォントは、独自のディレクトリのいずれかに配置し、独自のパスにフォントを置き換えることができる
font = r'/Users/piqianchao/Desktop/spider/SimHei.ttf'
wc = WordCloud(collocations=False, font_path=font, #
max_words=2000,width=4000,
height=4000, margin=2).generate(text.lower())
plt.imshow(wc)
plt.axis("off")
plt.show()
wc.to_file('.png') # ワードクラウドを保存する
予備結果
写真の音符は本当にウインクしています!
これは、私がPythonの日記をたくさん書いているからです。「活用する、実施する、データ分析」という他の3つの単語が目立つのは、『Pythonによるデータ分析』という本を読んだからです。
さらなる処理
マッピングの前に、価値のない情報をいくつか削除し、背景イメージを選択:
noUse = ["ノート"、"使用"、"作る"、"パンチ"、"ノート"、"学ぶ"]
for col in noUse:
while col in jieba_name:
jieba_name.remove(col)
from os import path
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
d = path.dirname('.') # ideでこのコードを使用する
# d = path.dirname(__file__)
# 保留中のドキュメント
text = " ".join(i for i in jieba_name)
# read the mask / color image taken from
# http://..//-----10
alice_coloring = np.array(Image.open(path.join(d, "wordcloud.png")))
# 無効語を設定する
stopwords = set(STOPWORDS)
stopwords.add("said")
# パスは、自分のものに変更された
font = r'/Users/piqianchao/Desktop/spider/SimHei.ttf'
# あなたは、マスクパラメータで単語雲の形状を設定することができる
wc = WordCloud(background_color="white", font_path=font,
max_words=2000, mask=alice_coloring,
height=6000,width=6000,
stopwords=stopwords, max_font_size=40, random_state=42)
# generate word cloud
wc.generate(text)
# create coloring from image
image_colors = ImageColorGenerator(alice_coloring)
# show
# セットマスクのみの場合、写真の形をしたワードクラウドが得られる
plt.imshow(wc, interpolation="bilinear")
plt.axis("off")
plt.show()
wc.to_file('_one.png') # ワードクラウドを保存する
# recolor wordcloud and show
# we could also give color_func=image_colors directly in the constructor
# コンストラクタで直接色を指定する:こうすることで、ワードクラウドは指定されたイメージのカラーレイアウトに従ってフォントのカラー戦略を生成する。
plt.imshow(wc.recolor(color_func=image_colors), interpolation="bilinear")
plt.axis("off")
plt.show()
wc.to_file('_two.png') # ワードクラウドを保存する
結論
これは上の最適化されたグラフで見ることができます:
- Pythonが最も有名です。実際、多くの記事がPythonについて書かれています。
- Pythonによるデータ分析』という本と、パンダの記事がたくさんあったからです。
- MySQL、SQL、Sqlzoo、データベースなどなど。
- マシンという言葉は機械学習から来ていて、ングさんのビデオでアルゴリズムやデータ構造など、入門的な知識をたくさん学びました。
- 深圳という言葉は、深圳に来てから深圳に関する記事をたくさん書いたことが主な理由です。
" "





