RealPath:
WebPath:
2017/05/21 20:03 (JST) 更新
Tipsその3 >>

スクレイピング結果を返すWebAPIを作ってみる

Contents

ひとつの実践サンプルとして、特定の Web ページをスクレイピングした結果を返す WebAPI を作ってみます。

CsQuery によるスクレイピング

CsQuery という NuGet ライブラリを使うことにより、HTML を jQuery っぽいセレクタ構文で要素分析することができます。

GitHub Trend を一覧取得してみる

今回は https://github.com/trending から取得できる HTML を解析し、プロジェクト情報の一覧を取得することを試みます。

スクレイピング単体実験用プロジェクトの作成

まずは単体のコンソールプロジェクトでスクレイピングの単体実験してみることをお勧めします(Webプロジェクトよりも軽いので試行錯誤しやすい)。

CsQuery の導入

プロジェクトを開いた状態で、
Views - Other Windows - Package Manager Console メニューから、Package Manager Console を開き、以下コマンドを実行します。

PM> Install-Package CsQuery

スクレイピングサンプル

Program.cs
using CsQuery;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.Run(async () =>
            {
                // インターネットリソースの取得
                string url = "https://github.com/trending";
                HttpClient client = new HttpClient();
                client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "*");
                client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36");
                HttpResponseMessage response = await client.GetAsync(url);
                string responseText = await response.Content.ReadAsStringAsync();

                // CsQuery による HTML パース
                var cq = new CQ(responseText);
                var items = cq.Find("h3 a");
                items.Each((e) => {
                    Console.WriteLine("----");
                    Console.WriteLine(e.InnerText.Trim());
                    Console.WriteLine(e.Attributes["href"]);
                });
            }).Wait();
        }
    }
}
実行結果
----
kotlin
/JetBrains/kotlin
----
react-pdf
/diegomura/react-pdf
----
preact-cli
/developit/preact-cli
----
ZZYQRCode
/zhang28602/ZZYQRCode
----
asm-dom
/mbasso/asm-dom
....

WebAPI としての実装

Web API を有効化した状態の ASP.NET MVC プロジェクトを作り、上記で取得したような一覧を返す WebAPI を実装してみます。

  1. Controllers フォルダを右クリック - [Add] - [Controller...] を選択。
  2. [Web API 2 Controller with read/write actions] を選択し [Add] を押下。
  3. Controller name には TrendsController と入力し、[Add] を押下。
  4. TrendsController.cs ができるのを確認。
  5. TrendsController を以下のように書き換え。
Controller/TrendsController.cs
using CsQuery;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;

namespace Controllers
{
    public class Trend
    {
        public string Name { get; set; }
        public string Url { get; set; }
    }

    public class TrendsController : ApiController
    {
        // GET: api/Trends
        public async Task<List<Trend>> Get()
        {
            // インターネットリソースの取得
            string url = "https://github.com/trending";
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "*");
            client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36");
            HttpResponseMessage response = await client.GetAsync(url);
            string responseText = await response.Content.ReadAsStringAsync();

            // CsQuery による HTML パース
            List<Trend> trends = new List<Trend>();
            var cq = new CQ(responseText);
            var items = cq.Find("h3 a");
            items.Each((e) => {
                trends.Add(new Trend { Name = e.InnerText.Trim(), Url = "https://github.com" + e.Attributes["href"] });
            });

            return trends;
        }
    }
}

動作確認

プログラムを起動し、http://localhost:*/api/Trends に手動でアクセス。

以下のような結果が得られます。

結果例
<ArrayOfTrend xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WebApplication30.Controllers">
<Trend>
<Name>kotlin</Name>
<Url>https://github.com//JetBrains/kotlin</Url>
</Trend>
<Trend>
<Name>react-pdf</Name>
<Url>https://github.com//diegomura/react-pdf</Url>
</Trend>

JavaScript からの実験

以下 JavaScript を Chrome 等のコンソールで実行してみます。

fetch('/api/Trends').then(function (response) {
    return response.json();
}).then(function (trends) {
    trends.forEach(function (t){
        console.log('----');
        console.log(t.Name);
        console.log(t.Url);
    });
});
結果例
----
kotlin
https://github.com//JetBrains/kotlin
----
react-pdf
https://github.com//diegomura/react-pdf
----
preact-cli
https://github.com//developit/preact-cli
----
ZZYQRCode
https://github.com//zhang28602/ZZYQRCode