BETA

Nimでスクレイピング

投稿日:2018-12-17
最終更新:2018-12-24

この記事は何?

仕様

  • QiitaのAdvent CalendarのURL(複数可)を指定すると、投稿または投稿予定の一覧を表示するCUIのコマンドを作成する。
  • 引数を省略すると、今年のNimのAdvent Calendarを対象にする。
  • コマンド名はadventとする。

コマンドライン処理

  • コマンドライン引数からURLを読み込む処理を実装する。
  • とりあえず、読み込んだURLを表示する。
import parseopt  

var urls: seq[string]  

for kind, key, value in getOpt():  
  case kind  
    of cmdArgument:  
      urls.add key  
    of cmdLongOption, cmdShortOption, cmdEnd:  
      discard  
if urls.len == 0:  
  urls.add "https://qiita.com/advent-calendar/2018/nim"  
echo urls  
  • 引数無し時のWandboxでの実行結果
@["https://qiita.com/advent-calendar/2018/nim"]  
  • Wandboxでのコマンドライン引数は、Runtime options:で指定する(1行に1つの引数を書く)
  • 引数がある時のWandboxでの実行結果
@["https://qiita.com/advent-calendar/2016/nim", "https://qiita.com/advent-calendar/2017/nim"]  
  • あってるっぽい。

HTMLを読み込む

  • 指定したURLからHTMLを読み込む処理を実装する。
  • とりあえず、読み込んだHTMLを表示する。
import httpclient    
import parseopt  

var urls: seq[string]  

for kind, key, value in getOpt():  
  case kind  
    of cmdArgument:  
      urls.add key  
    of cmdLongOption, cmdShortOption, cmdEnd:  
      discard  
if urls.len == 0:  
  urls.add "https://qiita.com/advent-calendar/2018/nim"  

let client = newHttpClient()  
for url in urls:  
  let response = client.get(url)  
  echo response.body  
  • 読み込むためのURLがhttpsから始まっているのでSSL通信が必要であり、その場合、ビルドオプションに-d:sslが必要。
  • Wandboxでは言語ごとにありがちなビルドオプションはあらかじめ指定されている。それに追加するにはCompiler options:で指定する(1行に1つのオプションを書く)
  • ただ、残念ながら、Wandboxでは実行時に名前解決できないエラーになった。
  • ローカルでは、ソースファイルをadvent.nimという名前で保存し、nim c -d:ssl adventとするとビルドできる。
  • 引数無し時の、自分のMacBookでの実行結果。
<!DOCTYPE html><html xmlns:og="http://ogp.me/ns#"><head><meta charset="UTF-8" /><title>Nim Advent Calendar 2018 - Qiita</title><meta content="width=device-width,initial-scale=1" name="viewport" /><meta content="[](https://nim-lang.org)  
Nimに関してなら何でもおっけー" name="description" /><meta content="#55c500" name="theme-color" /><meta content="summary" name="twitter:card" /><metacontent="@Qiita" name="twitter:site" /><meta content="Nim Advent Calendar 2018 - Qiita" property="og:title" /><meta content="article" property="og:type" /><meta content="https://qiita.com/advent-calendar/2018/nim" property="og:url" /><meta content="https://cdn.qiita.com/assets/qiita-fb-2887e7b4aad86fd8c25cea84846f2236.png" property="og:image" /><meta content="[](https://nim-lang.org)  
Nimに関してなら何でもおっけー" property="og:description" /><meta content="Qiita" property="og:site_name" /><meta content="564524038" property="fb:admins" /><link rel="canonical" href="https://qiita.com/advent-calendar/2018/nim" /><link rel="shortcut icon" type="image/x-icon" href="https://cdn.qiita.com/assets/favicons/public/production.ico" /><link rel="apple-touch-icon" type="image/png" href="https://cdn.qiita.com/assets/favicons/public/apple-touch-icon-f9a6afad761ec2306e10db2736187c8b.png" /><link rel="alternate" type="application/atom+xml" title="Atom Feed" href="https://qiita.com/advent-calendar/2018/nim/feed" /><link href="/opensearch.xml" rel="search" title="Qiita" type="application/opensearchdescription+xml" /><link rel="stylesheet" media="all" href="https://cdn.qiita.com/assets/public-f7a1573d8ac5d716970843e4cf66eed3.min.css" /><meta name="csrf-param" content="authenticity_token" />  
<meta name="csrf-token" content="eG564kNuIopu1Gc8TTeGZ0cwUG60BZ7IsAAKWXETbg5a+puw6CzeVPODUBhJcjYJcT94vQI3M9h/g0ir2x9QtA==" /><script>  
  window.gtmDataLayer = [  
    {  
      'analytics.dimension5': 'false',  
      'app.env': 'production',  
      'app.layoutVersion': 1,  
      'app.userId': null  
(後略)  
  • あってるっぽい。

HTMLからAdvent Calendarのタイトルを取得する

  • HTMLをパースするためのライブラリをインストールするために、コマンドラインでnimble install nimqueryを実行する。
  • パースしてAdvent Calendarのタイトルを取得する処理を実装する。
  • とりあえず、取得したタイトルを表示する。
import httpclient    
import htmlparser  
import parseopt  
import streams  
import xmltree  

import nimquery  

var urls: seq[string]  

for kind, key, value in getOpt():  
  case kind  
    of cmdArgument:  
      urls.add key  
    of cmdLongOption, cmdShortOption, cmdEnd:  
      discard  
if urls.len == 0:  
  urls.add "https://qiita.com/advent-calendar/2018/nim"  

let client = newHttpClient()  
for url in urls:  
  let response = client.get(url)  
  let xml = response.body.newStringStream().parseHtml()  
  let titleNode = xml.querySelector("[class=\"adventCalendarJumbotron_heading\"]")  
  if titleNode.isNil:  
    continue  
  echo titleNode.innerText  
  • 引数無し時の、自分のMacBookでの実行結果。
Nim Advent Calendar 2018  
  • あってるっぽい。

HTMLから投稿または投稿予定の一覧を取得する

  • HTMLをパースして投稿または投稿予定を取得する処理を実装する。
  • 取得したタイトルと投稿または投稿予定を表示する。
import httpclient    
import htmlparser  
import parseopt  
import streams  
import xmltree  

import nimquery  

var urls: seq[string]  

for kind, key, value in getOpt():  
  case kind  
    of cmdArgument:  
      urls.add key  
    of cmdLongOption, cmdShortOption, cmdEnd:  
      discard  
if urls.len == 0:  
  urls.add "https://qiita.com/advent-calendar/2018/nim"  

let client = newHttpClient()  
for url in urls:  
  let response = client.get(url)  
  let xml = response.body.newStringStream().parseHtml()  
  let titleNode = xml.querySelector("[class=\"adventCalendarJumbotron_heading\"]")  
  if titleNode.isNil:  
    continue  
  echo titleNode.innerText  
  let items = xml.querySelectorAll("[class=\"adventCalendarItem\"]")  
  for item in items:  
    let dateNode = item.querySelector("[class=\"adventCalendarItem_date\"]")  
    if dateNode.isNil:  
      continue  
    let dateText = dateNode.innerText  
    let date = dateText.substr(dateText.high - 1)  
    let authorNode = item.querySelector("[class=\"adventCalendarItem_author\"]")  
    let author = if authorNode.isNil: "" else: " by " & authorNode.attr("href").substr(1)  
    var entryNode = item.querySelector("[class=\"adventCalendarItem_entry\"]")  
    if entryNode.isNil:  
      entryNode = item.querySelector("[class=\"adventCalendarItem_comment\"]")  
    let entry = if entryNode.isNil: "" else: " " & entryNode.innerText  
    echo date & entry & author  
  echo ""  
  • a = if どうとか: b else: cみたいな書き方が若干キモい。
  • 引数無し時の、自分のMacBookでの実行結果。
Nim Advent Calendar 2018  
 1 Nimの非同期を改善したかった by 2vg  
 2 2011年時点での日本国民による Nim 啓蒙活動  by takano32  
 3 AWS Lambda 新機能 Custom Runtime を作ってみた  by sonodar  
 4 Nimの引数渡しの罠  by flat_leon  
 5 初心者による何か by kirk3110  
 6 12/11時点で空いてるので、なんか書きます。12/16くらいに投稿予定。 by ishidakei  
 7 Nim で プロファイリング結果を FlameGraph にする  by sessions  
 8 Nimでのファイル列挙  by ishidakei  
 9 Nimで地味に便利な関数とか by mkanenobu  
10 nimのpragmaについて by gmShiba  
11 どこでもNim by 6in  
12 Nimからコマンドプロンプト/ターミナルを起動する by 6in  
13 Nimで動的ライブラリに依存しないLinuxコマンドを作成する方法 by 6in  
14 軽快に動くNimのREPLを作った by gmShiba  
15 実践Nimマクロ by gmShiba  
16 NimとC言語の連携 by tlllune  
17 Jestyをただの静的HTTPサーバーとして動かす+musl by 6in  
18 Nim + Arraymancer + Cifar10 by cashiwamochi  
19 なんか書く予定 by 6in  
20 nimxについてなにか書きたい by aosa4054  
21 やっぱり自分の今Nimで作ろうとしているものについて語ろうと思います。 by manzyun  
22 Nimを使ったGUI作成について書こうかと by Blacpans  
23 NimのConceptについて by mrsekut  
24 俺がNimや by 2vg  
25  by 2vg  
  • 引数をhttps://qiita.com/advent-calendar/2016/nim https://qiita.com/advent-calendar/2017/nimにした状態での、自分のMacBookでの実行結果。
Nim Advent Calendar 2016  
 1 Nimの簡単な紹介 by snowlt23  
 2 「コロン系」の5言語を概観 (☆1) by Nimimal  
 4 Nimでのメイン処理とコマンドライン引数について by 6in  
 5 Nimで拡張子検索ツールを作ってみる by 6in  
 6 Nimで他の言語との連携方法まとめ by snowlt23  
 7 Nimでファイル内文字列置換ツールを作る by 6in  
 8 Nimで2Way-SQL的なPostgreSQLクライアントを作ってみる by 6in  
 9 NimのAsyncHttpServerで遊ぼうとしてみたら by 6in  
11 JavaからJNI経由でNimを呼び出してみる by 6in  
12 「IoTフロントエンド開発」を考えるシリーズ ①IoT時代の実装言語Nim by Nimimal  
13 「IoTフロントエンド開発」を考える ②nimyamlとnimongo by Nimimal  
14 Nimでファイルの文字コードを(外部ライブラリを利用して)判定する by 6in  
15 (年明けから)Pythonと共にNimを学ぶ。 by Nimimal  
18 json を扱う時の話  by CORDEA  
19 (随時更新) Nimを活用したUI/UX開発をCoreFoundation経由で。 by Nimimal  
21 項書き換えマクロで最適化 by snowlt23  
22 Objective-C その可能性の中心を,WinObjCとNimで...探りはじめる。 (「IoTフロントエンド開発」シリーズ ③) by Nimimal  
23 Nim の GUIライブラリ nimxをインストールしてサンプルコードを動かしてみる(2)  by haiju  
24 pegs について  by CORDEA  
25 Nim の GUIライブラリ nimxをインストールしてサンプルコードを動かしてみる(3)  by haiju  

Nim Advent Calendar 2017  
 1 Nim初心者がメタプログラミングに挑戦してみた by shti_f  
 3 lib/packages/docutils/rstast.nim の感想文を書くと思います。  by manzyun  
 4 Dockerで雑にNim with Neovim by Nimimal  
 5 AtCoder初心者向け問題をNimで解いてみた by shti_f  
11 Nimをインストールしてみる by nemui-fujiu  
15 【Nim】個人的逆引きリファレンス  by flat_leon  
16 競プロに疲れた人の Nim言語  by sessions  
17 NimとC++を比較してみる  by flat_leon  
18 Nimで速いWebサーバーを書くのです(両手を大きく広げ、輝く) by 2vg  
19 Nim Tutorial Part Iを日本語訳してみた(後編) by KTakahiro1729  
20 Nimクロスコンパイルのやり方 by hatchet  
21 Nim非同期I/Oを使う by horitaku1124  
22 Nim入門 (1) by nemui-fujiu  
23 Nim入門 (2) by nemui-fujiu  
24 DockerCompose + Nim + Jester + Nginxの環境を作る by nemui-fujiu  
25 Python使いで『今後はデータビジネスの現場かも』って人、NimData/Arraymancerをさわってみておこう。 by Nimimal  
  • あってるっぽい。
  • エラー処理をろくにしてないが、仕様は満たした気がするので、これにして完了。

補足

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@ishidakeiの技術ブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!