初めに
今回のスクレイピング対象は、QiitaのJuliaタグページです。
当初は、Zennの場合と同様に、HTMLから見出しとリンクを抜き出すことを考えました。
しかし、HTMLソースを見てみると、画面に表示されている「最近の投稿」に相当する情報が見当たりません。どうやら、Javascriptで動的に生成しているようです。(想像)
これでは、HTMLソースを取得して解析する方法が使えません。PyCall+selenium を使ってブラウザにJavascriptを解釈させて、DOMに展開された状態で処理する方法もありますが、今回は、Julia言語だけで処理することにします。
Qiitaでは、タグページにはフィードが提供されていて、新着記事の見出しやリンクの情報が含まれています。
フィードを解析するパッケージがあれば簡単なのですが、見つけられなかったので、XMLデータとして扱い、必要な情報を抜き出します。
使用するパッケージ
- HTTP
- HTTPを操作する(WebAPIを呼び出す)
- https://segakuin.com/julia/http/
- https://github.com/JuliaWeb/HTTP.jl
- EzXML
パッケージの追加
必要なパッケージを追加します。
julia> using Pkg
julia> Pkg.add("HTTP")
julia> Pkg.add("EzXML")
フィードの取得
指定URLからフィード(XMLファイル)を取得します。
julia> using HTTP
julia> qiita_feed = "https://qiita.com/tags/julia/feed"
julia> response = HTTP.request("GET", qiita_feed)
julia> code = String(response.body) # Byte列を文字列に変換
HTTPステータスコードが200のときに取得に成功したとみなします。
julia> response.status
200
XMLファイルの解析
取得したXMLを解析します。
文字列を解析した結果は EzXML.Document型で格納されます。
julia> using EzXML
julia> doc = parsexml(code)
julia> typeof(doc)
EzXML.Document
doc変数にEzXML.Document型が格納されています。
XMLのrootを抜き出します。対象のXMLファイルでrootに相当するタグは「feed」です。これでフィード本体の情報を取得することができました。
julia> feed = root(doc)
「feed」タグ以下の情報を含んだEzXML.Node型のデータが得られました。
julia> typeof(feed)
EzXML.Node
フィードの要素を順にチェックします
HTMLの時のようにCSSセレクターを使えないので、要素を一つ一つ確認しています。
「feed」タグの下に、複数の「entry」タグがあります。これがそれぞれの記事の情報を示しています。今回取得するのは、「entry」タグの下の「url」タグと「title」タグの内容です。
HTMLの場合のように深い階層構造になっていないので、一つ一つを確認してもそれほど大変な処理にはなりません。
次のコードで、見出しとリンクのタプルを要素とするリストが作成されます。もう少し効率の良い書き方があるかもしれませんが、わかりやすさを優先しました。
julia> begin
list = []
for tag in eachelement(feed)
if tag.name == "entry"
url = nothing
title = nothing
for item in eachelement(tag)
if item.name == "url"
url = item.content
elseif item.name == "title"
title = item.content
end
end
if !isnothing(url)
pair = (title, url)
push!(list, pair)
end
end
end
end
julia>
なお、フィードに書き込まれるURLは絶対パスなので、Zennの時のようなURLの補正の処理は不要です。
まとめ
上記をまとめたコードを下記に公開しています。
実行すると、日付付きのファイルにTSV形式で見出し+URLを出力します。
julialangjp/ScrapingQiitaTagByJulia (Github)
コメント