Product Advertising API(リンク作成用API)でアフィリコード取得
昨日まででなんとか、あるサイトのHTMLを取得して、
DOM構築して特定のキーワードを抜き出すことができた。
次はそのキーワードを元に、
楽天やアマゾンのアフィリコードを取得したい。
とりあえずアマゾンかな?
アマゾンのアフィリコード取得には、Product Advertising API(リンク作成用API)を使う。
説明はこちら⇒Product Advertising API
まずは特定キーワードからアフィリコードを取得してみた。
アフィリコードの取得にも、やっぱりXPathが役に立つんだね。
1.Product Advertising API(リンク作成用API)のアカウント作成
https://affiliate.amazon.co.jp/gp/advertising/api/detail/main.html
こちらから、まずはアカウント作成をします。
いつも買い物で使っているアマゾンのアカウントでOKです。
登録完了メールが来たらOKです。
2.とりあえずリクエストを作ってみた
とりあえず画像のサンプルに従ってリクエストを作ってみたら、
↓こんなエラーがかえって来た。
<?xml version="1.0"?> <ItemLookupErrorResponse xmlns="http://ecs.amazonaws.com/doc/2005-10-05/"><Error><Code>MissingParameter</Code><Message>The request must contain the parameter Signature.</Message></Error><RequestId>a7d5facf-7XXXXXX0057</RequestId></ItemLookupErrorResponse>
どうやら、APIの仕様が変わっているらしい。
しかもだいぶ前に。
↓↓Signature と Timestampというパラメータが必要になったらしい。
JavaでJTidy + XPathを使ってAタグのhref属性を取得してみた。
参考文献から。
javax.xml.xpath (Java Platform SE 6)
いかにXPathを使わないとなると、DOMの解析が面倒か分かる。
未だにうちの現場では面倒な方法でDOMの解析をしていた。
あーやれやれ。
・XPathの書き方はこちら
ここも整然としていてGood。
今日ははてなブログ(当ブログ)の発リンクのリンク先を取得しました。
DOMの構築はJTidyを使った。
JTidyでパースしないと、DOM構築時にExceptionが出てしまうから。
下記のようなメソッドを作った。
HTTPレスポンスをそのまま渡せばDOMを構築してくれる。
/**
* DOM構築
* @param inputStream HTTPレスポンスをそのまま
* @return Document 構築されたDOM
*/
private Document parseDomByTidy(InputStream inputStream) {
Tidy tidy = new Tidy();
tidy.setQuiet(true);
tidy.setShowWarnings(false);
tidy.setForceOutput(false);
return tidy.parseDOM(inputStream, null);
}
構築したDOMに対して、XPathでAタグのhrefをNodeListとして取得した。
NodeListはfor文で回して、Node#getNodeValue()でリンク先を取得した。
try {
// DOM構築
Document document = this.parseDomByTidy(inputStream);
// Xpath作成
XPath xpath = XPathFactory.newInstance().newXPath();
// ノードリスト取得
NodeList nodeList = (NodeList) xpath.evaluate(
"//a/@href", document, XPathConstants.NODESET);
// 1回目:各ノード内容表示
System.out.println("aタグの数:" + nodeList.getLength());
for (int i = 0; i < nodeList.getLength(); i++) {
Node aTagNode = nodeList.item(i);
System.out.println(aTagNode.getNodeValue());
}
// ノードリスト取得
System.out.println("★<h1>タグ内の<a>タグを抽出★");
nodeList = (NodeList) xpath.evaluate(
"//h1/a/@href", document, XPathConstants.NODESET);
// 2回目:各ノード内容表示
System.out.println("aタグの数:" + nodeList.getLength());
for (int i = 0; i < nodeList.getLength(); i++) {
Node aTagNode = nodeList.item(i);
System.out.println(aTagNode.getNodeValue());
}
} finally {
inputStream.close();
}
実行結果(コンソール)は↓↓
line 119 column 9 - Error: <header> is not recognized!
line 147 column 17 - Error: <article> is not recognized!
line 149 column 5 - Error: <header> is not recognized!
line 152 column 12 - Error: <time> is not recognized!
aタグの数:97
#
http://noric0124.hatenablog.jp/
http://noric0124.hatenablog.jp/entries/2013/12/18
http://noric0124.hatenablog.jp/entry/2013/12/18/%E3%83%A4%E3%83%95%E3%83%BC%E3%82%88%E3%82%8A%E3%82%82%E7%B0%A1%E5%8D%98%E3%81%AAHTML%E3%82%92JTidy%E3%81%A7DOM%E8%A7%A3%E6%9E%90%E3%80%82
http://www.html-cool.com/samples/tryhtml_basic.html
http://www.html-cool.com/samples/tryhtml_basic.html
http://noric0124.hatenablog.jp/entry/2013/12/18/%E3%83%A4%E3%83%95%E3%83%BC%E3%82%88%E3%82%8A%E3%82%82%E7%B0%A1%E5%8D%98%E3%81%AAHTML%E3%82%92JTidy%E3%81%A7DOM%E8%A7%A3%E6%9E%90%E3%80%82
http://blog.hatena.ne.jp/guide/pro
http://noric0124.hatenablog.jp/entries/2013/12/18
http://noric0124.hatenablog.jp/entry/2013/12/18/JTidy%E3%81%AFSAX%E3%81%98%E3%82%83%E3%81%AA%E3%81%8F%E3%81%A6DOM
http://sourceforge.jp/projects/sfnet_jtidy/
http://d.hatena.ne.jp/keyword/Google%CB%DD%CC%F5
http://d.hatena.ne.jp/keyword/Java
http://d.hatena.ne.jp/keyword/Java
http://noric0124.hatenablog.jp/entry/2013/12/18/JTidy%E3%81%AFSAX%E3%81%98%E3%82%83%E3%81%AA%E3%81%8F%E3%81%A6DOM
http://noric0124.hatenablog.jp/entries/2013/12/18
http://noric0124.hatenablog.jp/entry/2013/12/18/DOM%E3%81%A8SAX%E3%81%AF%E9%81%95%E3%81%86%E3%80%82
http://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%EC%A5%A4%A5%D4%A5%F3%A5%B0
http://www.atmarkit.co.jp/ait/articles/0208/20/news002.html
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/API
http://d.hatena.ne.jp/keyword/%A5%C7%A5%D5%A5%A1%A5%AF%A5%C8%A5%B9%A5%BF%A5%F3%A5%C0%A1%BC%A5%C9
http://d.hatena.ne.jp/keyword/Document%20Object%20Model
http://d.hatena.ne.jp/keyword/API
http://d.hatena.ne.jp/keyword/API
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/API
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/%B9%BD%CA%B8%B2%F2%C0%CF
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%EC%A5%A4%A5%D4%A5%F3%A5%B0
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/XPath
http://d.hatena.ne.jp/keyword/XQuery
http://noric0124.hatenablog.jp/entry/2013/12/18/DOM%E3%81%A8SAX%E3%81%AF%E9%81%95%E3%81%86%E3%80%82
http://noric0124.hatenablog.jp/entries/2013/12/17
http://noric0124.hatenablog.jp/entry/2013/12/17/JTidy%E3%82%92%E4%BD%BF%E3%81%88%E3%81%B0DOM%E3%81%8C%E6%A7%8B%E7%AF%89%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%89%E3%81%97%E3%81%84%E3%80%82
http://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%D6%A5%ED%A5%B0
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/IBM
http://d.hatena.ne.jp/keyword/IBM
http://www.ibm.com/developerworks/jp/java/library/j-jtp03225/
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/XPath
http://sourceforge.jp/projects/sfnet_jtidy/
http://d.hatena.ne.jp/keyword/IBM
http://noric0124.hatenablog.jp/entry/2013/12/17/JTidy%E3%82%92%E4%BD%BF%E3%81%88%E3%81%B0DOM%E3%81%8C%E6%A7%8B%E7%AF%89%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%89%E3%81%97%E3%81%84%E3%80%82
http://noric0124.hatenablog.jp/entries/2013/12/15
http://noric0124.hatenablog.jp/entry/2013/12/15/%E3%83%A4%E3%83%95%E3%83%BC%E3%82%82DOM%E8%A7%A3%E6%9E%90%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%9F%E3%82%89%E3%80%81SAXParseException%E3%80%82
http://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%D6%A5%ED%A5%B0
http://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%EC%A5%A4%A5%D4%A5%F3%A5%B0
http://noric0124.hatenablog.jp/entry/2013/12/15/%E3%83%A4%E3%83%95%E3%83%BC%E3%82%82DOM%E8%A7%A3%E6%9E%90%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%9F%E3%82%89%E3%80%81SAXParseException%E3%80%82
http://noric0124.hatenablog.jp/entries/2013/12/15
http://noric0124.hatenablog.jp/entry/2013/12/15/%E3%81%AF%E3%81%A6%E3%81%AA%E3%83%96%E3%83%AD%E3%82%B0%E3%82%92DOM%E8%A7%A3%E6%9E%90%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%9F%E3%82%89%E3%80%81SAXParseException%E3%80%82
http://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%D6%A5%ED%A5%B0
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/IBM
http://www.ibm.com/developerworks/jp/xml/library/x-saxerror.html
http://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%D6%A5%ED%A5%B0
http://d.hatena.ne.jp/keyword/XML
http://noric0124.hatenablog.jp/entry/2013/12/15/%E3%81%AF%E3%81%A6%E3%81%AA%E3%83%96%E3%83%AD%E3%82%B0%E3%82%92DOM%E8%A7%A3%E6%9E%90%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%9F%E3%82%89%E3%80%81SAXParseException%E3%80%82
http://noric0124.hatenablog.jp/entries/2013/12/13
http://noric0124.hatenablog.jp/entry/2013/12/13/XML%E8%A7%A3%E6%9E%90%E3%81%A7%E3%81%AF%E3%80%81%E7%B5%B6%E5%AF%BE%E3%81%ABXPath%E3%82%92%E4%BD%BF%E3%81%84%E3%81%9F%E3%81%84%E3%80%82
http://d.hatena.ne.jp/keyword/XPath
http://d.hatena.ne.jp/keyword/W3C
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%EC%A5%A4%A5%D4%A5%F3%A5%B0
http://d.hatena.ne.jp/keyword/XPath
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/XPath
http://d.hatena.ne.jp/keyword/XPath
http://d.hatena.ne.jp/keyword/XPath
http://d.hatena.ne.jp/keyword/XML
http://d.hatena.ne.jp/keyword/XPath
http://ja.wikipedia.org/wiki/XML_Path_Language
http://www.techscore.com/tech/XML/XPath/XPath1/xpath01.html/
http://noric0124.hatenablog.jp/entry/2013/12/13/XML%E8%A7%A3%E6%9E%90%E3%81%A7%E3%81%AF%E3%80%81%E7%B5%B6%E5%AF%BE%E3%81%ABXPath%E3%82%92%E4%BD%BF%E3%81%84%E3%81%9F%E3%81%84%E3%80%82
http://noric0124.hatenablog.jp/?page=1386946668
http://noric0124.hatenablog.jp/about
http://noric0124.hatenablog.jp/about
#
http://hatenablog.com/
http://blog.hatena.ne.jp/register?via=200109
http://staff.hatenablog.com/
http://noric0124.hatenablog.jp/archive
http://noric0124.hatenablog.jp/entry/2013/12/18/%E3%83%A4%E3%83%95%E3%83%BC%E3%82%88%E3%82%8A%E3%82%82%E7%B0%A1%E5%8D%98%E3%81%AAHTML%E3%82%92JTidy%E3%81%A7DOM%E8%A7%A3%E6%9E%90%E3%80%82
http://noric0124.hatenablog.jp/entry/2013/12/18/JTidy%E3%81%AFSAX%E3%81%98%E3%82%83%E3%81%AA%E3%81%8F%E3%81%A6DOM
http://noric0124.hatenablog.jp/entry/2013/12/18/DOM%E3%81%A8SAX%E3%81%AF%E9%81%95%E3%81%86%E3%80%82
http://noric0124.hatenablog.jp/entry/2013/12/17/JTidy%E3%82%92%E4%BD%BF%E3%81%88%E3%81%B0DOM%E3%81%8C%E6%A7%8B%E7%AF%89%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%89%E3%81%97%E3%81%84%E3%80%82
http://noric0124.hatenablog.jp/entry/2013/12/15/%E3%83%A4%E3%83%95%E3%83%BC%E3%82%82DOM%E8%A7%A3%E6%9E%90%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%9F%E3%82%89%E3%80%81SAXParseException%E3%80%82
http://noric0124.hatenablog.jp/archive
http://noric0124.hatenablog.jp/about
http://hatenablog.com/
http://d.hatena.ne.jp/
★
<h1>タグ内の<a>タグを抽出★
aタグの数:8
http://noric0124.hatenablog.jp/
http://noric0124.hatenablog.jp/entry/2013/12/18/%E3%83%A4%E3%83%95%E3%83%BC%E3%82%88%E3%82%8A%E3%82%82%E7%B0%A1%E5%8D%98%E3%81%AAHTML%E3%82%92JTidy%E3%81%A7DOM%E8%A7%A3%E6%9E%90%E3%80%82
http://noric0124.hatenablog.jp/entry/2013/12/18/JTidy%E3%81%AFSAX%E3%81%98%E3%82%83%E3%81%AA%E3%81%8F%E3%81%A6DOM
http://noric0124.hatenablog.jp/entry/2013/12/18/DOM%E3%81%A8SAX%E3%81%AF%E9%81%95%E3%81%86%E3%80%82
http://noric0124.hatenablog.jp/entry/2013/12/17/JTidy%E3%82%92%E4%BD%BF%E3%81%88%E3%81%B0DOM%E3%81%8C%E6%A7%8B%E7%AF%89%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%89%E3%81%97%E3%81%84%E3%80%82
http://noric0124.hatenablog.jp/entry/2013/12/15/%E3%83%A4%E3%83%95%E3%83%BC%E3%82%82DOM%E8%A7%A3%E6%9E%90%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%9F%E3%82%89%E3%80%81SAXParseException%E3%80%82
http://noric0124.hatenablog.jp/entry/2013/12/15/%E3%81%AF%E3%81%A6%E3%81%AA%E3%83%96%E3%83%AD%E3%82%B0%E3%82%92DOM%E8%A7%A3%E6%9E%90%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%9F%E3%82%89%E3%80%81SAXParseException%E3%80%82
http://noric0124.hatenablog.jp/entry/2013/12/13/XML%E8%A7%A3%E6%9E%90%E3%81%A7%E3%81%AF%E3%80%81%E7%B5%B6%E5%AF%BE%E3%81%ABXPath%E3%82%92%E4%BD%BF%E3%81%84%E3%81%9F%E3%81%84%E3%80%82
正常終了です。
終了時刻:Thu Dec 19 00:44:34 JST 2013
という結果だった。
1回目はとにかくすべてのaタグのリンク先を抜き出した。
すると97件出てきた。多すぎる。
2回目ではh1タグ内にあるaタグに絞って抜き出した。
すると8件。
これは各記事タイトルに相当している。
特に意味のあるデータではないが、
XPathの練習としてやってみたました。
XPathはNodeListの取得が簡単にできるので、
表記法に慣れれば相当便利です。
ただし、最終的にはfor文で回さないといけないのが、
どうもまだ面倒な気がしますね。
もっと楽になるという記事を読みました。
後々そちらにも挑戦していこうかな。
ヤフーよりも簡単なHTMLをJTidyでDOM解析。
ヤフーのHTMLははっきり言って読みにくいです。
なのでまずはJTidyに慣れるために、
動作確認の意味も込めて、もっと簡単なHTMLを解析しましょう。
HTML サンプル で検索してでてきたのが↓↓こちら。
http://www.html-cool.com/samples/tryhtml_basic.html
上記サイトのHTMLをInputStreamとして下記のメソッドに渡しました。
Tidy tidy = new Tidy();
tidy.setQuiet(true);
tidy.setShowWarnings(false);
tidy.setForceOutput(true);
Document tidyDOM = tidy.parseDOM(inputStream, null);
System.out.println(tidyDOM.getElementsByTagName("script").getLength());
System.out.println(tidyDOM.getElementsByTagName("body").getLength());
System.out.println(tidyDOM.getElementsByTagName("form").getLength());
実行したところ、コンソールには
4
1
1
と出ました。
http://www.html-cool.com/samples/tryhtml_basic.htmlをブラウザで開いて、
ソースを見てみて欲しいのですが、
<script> タグは確かに4つあります。 ⇒ OK
<body> タグは2つ。 ⇒ ? ⇒ textareaタグ内はカウントされない模様 ⇒ OK
<form> タグは確かに1つあります。 ⇒ OK
なので、JTidyでのDOM構築に成功していると言えます。
また、気になる事がtidy#parseDOMしたときにエラーが出た場合です。
下記の画像のように、今回正常にDOM構築できたわけではなく、
3つほどエラーが出力されています。
エラー内容は、「そのタグの位置おかしいよ」的なことです。
しかし、そのエラーが出た後に、
4
1
1
という結果が出ているので、
エラーが出たとしてもDOMは構築できた!ということです。
これが私が欲しかった結果でした^^
明日またヤフーの解析にチャレンジしてみます。
JTidyはSAXじゃなくてDOM
前回SAXとDOMの違いを調べてみました。
昨日、JTidyでヤフーをDOM解析しようとしていたので、
JTidyはSAXとDOMのどちら?と思って調べたら、DOMでした。
JTidyの日本語サイトに書いてあること、
自分の直面している問題に対して、どストライクなんですよね。
↓↓以下、日本語おかしいですがGoogle翻訳しました。
『その場合は、HTML Tidy Java ポート、HTML 文法チェッカおよびかなりのプリンターです。その非 Java のいとこのようなその場合は不正と障害のある HTML をクリーンアップするためのツールとして使用できます。さらに、その場合は実際の html DOM パーサーを提供します。』
HTML文法に不正があってもDOM解析してくれる。
っていう認識でいいんですよね?
DOMとSAXは違う。
DOMとSAXが違うということは、薄々感づいていたのですが、
意識することなくいろんなサイトのソースをコピペして、
スクレイピングしようとしていました。
ですが、やはりDOMとSAXの違いというのは、
小さくなさそうなのでちょっと調べてみました。
・技術者のためのXML再入門(10):XMLプログラミングのためのAPI - @IT
XMLデータを操作するAPIとして、現在下記の2つがデファクトスタンダードとして利用されている。
・DOM (Document Object Model) ツリー・ベースのAPI
・SAX (Simple API for XML) イベント・ベースのAPI
XMLデータを一気に読み込んで構文解析し、メモリ上にツリーを展開する(このツリーを「DOMツリー」と呼ぶ)。
DOMでは、このメモリ上に展開されたDOMツリーにアクセスしたり、要素を追加・削除することでXMLデータの構造を変更することができる。
先頭から順にXMLデータを読み込んでいき、“要素の開始”や“要素の終わり”といったイベントを生成、その都度アプリケーションに通知する。
アプリケーションはそれらのイベントを受け取ったときの処理を定義しておき、イベントを受け取ったときに呼び出されて処理を行う。
メモリー消費 DOM > SAX
アクセス DOM ランダム、SAX 一方通行
なるほどー。同じXMLの解析するにしても、根本の発想は全然違うんですね。
今まで自分がやろうとしていたのは、DOMの考え方。
レスポンスをDOM化して、DOMの中の場所を指定して、必要な情報を得る方法。
でも、スクレイピングでの使用を考えると、
DOMを操作することはないですよね。
XML全体を1回なめて、必要な情報を抽出すればいいわけだから、
SAXの方がメモリ消費が少ないからよさそう。
読み込み効率もいいみたいだし。
でもSAXはSAX向けのプログラミングを覚えないといけないんだね。
そこがちょっとめんどくさい。
あれ?
JTidyを使えばDOMが構築できるらしい。
DOMが構築できない問題。
SAXParseExceptionが投げられてしまう。
別のパーサーを見つけた。
JTidyっていうやつ。
最高の参考文献はIBMさん。
IBMさんの技術文献はどれも優れていますよね。
Javaの理論と実践: XQueryによるscreen-scraping
「ほとんどどんなWebページも、XML文書として処理することができ、お好みのデータ抽出用XMLツール(SAXであれXSLであれXPath、どれでも)を適用することができます。」
最新のJTidyのDLはこちらから。
DLしてライブラリに追加するだけ。
JTidy プロジェクト日本語トップページ - SourceForge.JP
IBMさんのやり方でyahoo!のaタグの内容出そうとしてみた。
すると、エラーで落ちることはなかったけど、
エラーらしきものは出ている。↓↓
惜しいところまで来ている気がする。
明日また試してみよう。
ヤフーもDOM解析しようとしたら、SAXParseException。
あららです。
ヤフーさんでも、DOM解析に失敗してしまいます。
はてなブログさんだけならまだしも、ヤフーもダメってなると、
この↓↓自分のやり方がまずいんでしょうね。
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(inputStream);
いろんな入門サイト見たらこの方法でやってるのですが、
どうも実用性は低いみたいです。
ウェブスクレイピングへの道はいきなり険しいです。