最近TikTokなるものを始めてみたのですが、再生回数が表示されません。実はパソコンからだと通常の方法では動画の再生回数を確認することができないのです。どうしてこんなPCユーザーいじめのような仕様になっているのでしょうか?スマホでないと利用できないサービスが最近増えてきたように思います。
Contents
PCからでもTikTokの再生回数を確認できる
とはいえPCからでもTikTokの再生回数を確認する方法はあります。それはHTMLソースには書かれているのでそれを直接見ればよいのです。動画の投稿ページに移動して Ctrlキーを押しながら U キー を押下するとソースを見ることができます。
https://www.tiktok.com/@hatodemowakaru/video/7193925347593702657
Ctrl + F キーを押すとソース内の文字列を検索することができます。「playCount」を検索します。すると再生回数は777回だということがわかります。YouTubeだとたった2日でこんなに再生回数が増えることはないのでTikTokのほうが再生されやすいことがわかります。
HttpClientではTikTokのHTMLを取得できない?
あとはC#でHTMLを解析して再生回数を取得すれば目的は達成できそうです。
そこでこんなコードを書いてみました。
ところがこれだと文字列を取得することができません。他のサイトだとHTMLを取得することができるのですが、TikTokの場合はうまくいきません。
1 2 3 4 5 6 7 8 9 10 11 12 |
using System.Net; public partial class Form1 : Form { System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient(); private async void button1_Click(object sender, EventArgs e) { // うまくいかない string str = await httpClient.GetStringAsync("https://www.tiktok.com/@hatodemowakaru/video/7194571894694104321"); } } |
PuppeteerSharpをインストールする
そこで別の方法をとります。NuGetでPuppeteerSharpをインストールします。
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 |
using PuppeteerSharp; public partial class Form1 : Form { IBrowser Browser = null; public Form1() { InitializeComponent(); Task.Run(async ()=> { await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultChromiumRevision); LaunchOptions options = new LaunchOptions { Headless = true, }; Browser = await Puppeteer.LaunchAsync(options); }); } private async void button1_Click(object sender, EventArgs e) { // これならうまくいく IPage page = await Browser.NewPageAsync(); await page.GoToAsync("https://www.tiktok.com/@hatodemowakaru/video/7194571894694104321"); string html = await page.GetContentAsync(); page.Dispose(); } } |
再生数が書かれている部分はjsonデータでscriptタグで囲われています。そこでこの部分を抜き出します。
1 2 3 4 5 |
<script id="SIGI_STATE" type="application/json"> ここにjson形式で書かれている {"diggCount":17,"shareCount":0,"commentCount":0,"playCount":777} ほかにもいろいろ書かれている </script> |
json形式の文字列を抜き出すのであれば取得したHTML全体を <script id=”SIGI_STATE” type=”application/json”> で分割し、後ろ側の要素を </script> で分割して最初の要素を取得すればよいです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Form1 : Form { string GetJson(string html) { string[] sp = { "<script id=\"SIGI_STATE\" type=\"application/json\">" }; string[] vs = html.Split(sp, StringSplitOptions.RemoveEmptyEntries); if (vs.Length < 2) return ""; sp[0] = "</script>"; vs = vs[1].Split(sp, StringSplitOptions.RemoveEmptyEntries); if (vs.Length < 2) return ""; return vs[0]; } } |
また抜き出したJsonデータから再生回数を抜き出したいのであれば、文字列を「”playCount”:」で分割しその後ろ側の要素を「}」または「,」で分割して最初の要素を取得すればできそうです。
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 |
public partial class Form1 : Form { int GetPlayCount(string json) { return GetValueFromJson(json, "playCount"); } int GetValueFromJson(string json, string key) { // 想定外の場合はすべて -1 を返す if (json == "") return -1; string[] sp1 = { $"\"{key}\":" }; string[] vs = json.Split(sp1, StringSplitOptions.RemoveEmptyEntries); if (vs.Length < 2) return -1; string str = vs[1]; string[] sp2 = { "}", "," }; vs = str.Split(sp2, StringSplitOptions.RemoveEmptyEntries); if (vs.Length < 2) return -1; try { return int.Parse(vs[0]); } catch { return -1; } } } |
これらを使って再生数、いいね、シェア数を取得し、TextBoxに出力させるコードを示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public partial class Form1 : Form { private async void button1_Click(object sender, EventArgs e) { IPage page = await Browser.NewPageAsync(); await page.GoToAsync("https://www.tiktok.com/@hatodemowakaru/video/7194571894694104321"); string html = await page.GetContentAsync(); page.Dispose(); string json = GetJson(html); int playCount = GetValueFromJson(json, "playCount"); int diggCount = GetValueFromJson(json, "diggCount"); int shareCount = GetValueFromJson(json, "shareCount"); textBox1.Text = $"再生数:{playCount} いいね:{diggCount} シェア:{shareCount}" ; } } |
アップしている動画の再生数をすべて取得する
HTMLを調べてみるとアップしている動画の再生数をすべて取得することができることがわかりました。
https://www.tiktok.com/@hatodemowakaru/
HTMLの文字列のなかに「playCount」が複数存在します。また動画のタイトルも書かれているので、そのアカウントのすべての動画の再生数、いいね、シェア数を取得することができそうです。
先述のGetJsonメソッドで取得したjsonデータを開いてみると以下のようになります。
ItemModuleというキーのなかに動画のIDのキーがあり、そのなかにstatsというキーがあります。そのなかに再生数やいいねの数が記録されていることがわかります。この部分を抜き出せば必要な情報を得られそうです。
ここではNewtonsoft.Json.Linq.JObjectクラスを使います。
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 |
public partial class Form1 : Form { async void GetPlayInfos(string url) { IPage page = await Browser.NewPageAsync(); await page.GoToAsync(url); string html = await page.GetContentAsync(); string json = GetJson(html); Newtonsoft.Json.Linq.JObject document = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(json); string items = ""; foreach (var m in document) { if (m.Key == "ItemModule") { items = $"{m.Value}"; break; } } document = (JObject)JsonConvert.DeserializeObject(items); foreach (var m in document) { // ここで動画のタイトル、再生数、いいね、シェア数が取得できる GetInfoFromItem($"{m.Value}", out string title, out string playCount, out string diggCount, out string shareCount); // あとはこれをデータをして保存すればOK。 } } void GetInfoFromItem(string json, out string title, out string playCount, out string diggCount, out string shareCount) { title = ""; playCount = ""; diggCount = ""; shareCount = ""; JObject document = (JObject)JsonConvert.DeserializeObject(json); foreach (var m in document) { if (m.Key == "desc") title = $"{m.Value}".Split('#')[0]; if (m.Key == "stats") { JObject document2 = (JObject)JsonConvert.DeserializeObject($"{m.Value}"); foreach (var m2 in document2) { if (m2.Key == "playCount") playCount = $"{m2.Value}"; if (m2.Key == "diggCount") diggCount = $"{m2.Value}"; if (m2.Key == "shareCount") shareCount = $"{m2.Value}"; } } } } } |