読者です 読者をやめる 読者になる 読者になる

SITEINFOのnextLinkケーススタディ

AutoPagerize

AutoPagerizeのSITEINFOを書くとき、ネックになりがちなのはnextLinkのXPath
pageElementのXPathは割とシンプルに書ける*1し、insertBeforeは省略しても構わない。

というわけで、nextLinkのXPathのパターンを簡単にまとめてみる。

aタグを直接指定できるケース

次のページのURLを情報*2を含む要素を直接指定できるケース。精度が高く、メンテナンス面も優れる。

例:はてなダイアリー
AutoPagerize本体にも組み込まれている通り、aタグもしくは、linkタグのrel属性にnextが指定された要素を取得する。

    • html
<link rel="prev" href="/os0x/?of=5" title="前の5日分">
nextLink:     '//link[@rel="prev"]'

大抵nextとprevの両方があるが、そのどちらを使うかはサイトによってまちまち。
標準的で、間違いもないので、最も扱いやすいケース。

  • 次のページを指す要素に特定の属性(classやidなど)が指定されている

例:FFFFOUND! http://ffffound.com/

    • html
<a id="paging-next" rel="next" href="?offset=25&">next(<span class="shortcut">l</span>) &raquo;</a>
nextLink:     'id("paging-next")'

他には

'//a[@class="Next"]' //Flickr

や、

'//a[@accesskey="e"]' //(del.icio.us)

など。

  • 次のページのリンクに特定の文言、画像などが含まれる

nextなどの文言が含まれるAタグを指定する。text()を調べるのはパフォーマンスに難があるので、特定要素以下に限定するように工夫することが望ましい。
例:Engadget Japanese http://japanese.engadget.com/

    • html
<a href="/page/2/">次のページ</a>
nextLink:     '//a[starts-with(text(),"次の")]'

他には、

'id("navbar")//a[child::img[@src="nav_next.gif"]]' //(Google Blog Search)

など。人間にとってわかりやすい反面、サイトのちょっとした変更で動かなくなることがある。

aタグの何番目に位置するか指定するケース

次のページへのリンクを直接は指定できないが、その親にあたる要素を指定し、その最初か、最後などの特定位置にある要素を取得するパターン。
精度の面はやや心もとないが、汎用性は高くよく使われている。

  • ある要素を指定して、その最初の子要素を取得

例:Google

    • html
<td class="b" nowrap="">
<a href="/search?q=AutoPagerize&hl=ja&rlz=1B3GGGL_jaJP245JP246&pwst=1&start=10&sa=N"><div id="nn"/><b>次へ</b></a>
</td>
nextLink:     'id("navbar")//td[last()]/a'

ちなみ、上記の場合、

nextLink:     'id("nn")/..'

でも良い。

  • ある要素を指定して、その最後の子要素を取得

例:はてなブックマーク

    • html
<div class="pager">
<p> 1 <a>2</a> <a>3</a> ... <a>10</a>  <a href="./?of=20">次の20件&gt;</a>
</div>
nextLink:     '//div[@class="pager"][last()]//a[last()]'

兄弟要素から取得するケース

ページナンバーが1 2 3 ...と並んでいるだけの場合、次のページを特定することが難しい。
その場合、現在のページだけaタグ以外でマークアップされていることが多いので、そのタグを起点にその兄弟を取得することで次のページのURLを取得できる。
例:Softpedia http://www.softpedia.com/progSearch?src=firefox (oAutoPagerizeのみ)

    • html
<b>1</b> <a>2</a> <a>3</a> <a>4</a>
nextLink:     '//a[starts-with(@href,"/progSearch/")]/../b/following::a'

やや複雑だけど、Googleのようなページナビゲーションを使っているサイトでは汎用的に有効なので、困ったときはこの方法を試してみると良いかも。
[追記]
The art of AutoPagerize nextLink XPath writing « kuでさらなるアイディアを頂きました。
ちなみに上記の例は、following-siblingを使ったほうが良いですね。following-siblingは兄弟ノードのみ、followingでは兄弟ノードの子孫ノードも含まれます。

nextLink:     '//a[starts-with(@href,"/progSearch/")]/../b/following-sibling::a'

[/追記]

とりあえず、こんなところで。
ここまで書いてみて思ったのだが、XPathをパターン分けするのではなく、ページナビゲーションをパターン分けして、それに対するXPathを見たほうがわかりやすかったかもしれない。
デザインの視点も入れれば非常に面白く、わかりやすい記事になりそうなので誰かが書いてくれないかな。

*1:ただ、tableが入れ子になっていたり、HTMLが壊れているようなサイトでは最も難しくなる傾向があるのだが

*2:href、もしくはaction、value