19737


下記ページのHTMLには、`a[class ^= "history"]` オブジェクトが36個あることを確認しています。  
[http://ja.aliexpress.com/wholesale?catId=0&initiative_id=AS_20151205231131&SearchText=bag+mens](http://ja.aliexpress.com/wholesale?catId=0&initiative_id=AS_20151205231131&SearchText=bag+mens)

しかし、nokogiriのcssセレクタで、上記オブジェクトを取得すると4個しか取得できません。

原因がわからず、大変困っています。  
原因がわかるかた、いらっしゃいますでしょうか？

[code]

    require 'open-uri'
    require 'nokogiri'
    require 'pstore'
    require 'anemone'
    require 'open_uri_redirections'
    require 'openssl'
    
    class URLList
      def GetHtmlObj(url)
        charset = nil
        html = open(url, :allow_redirections => :safe, :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE) do |f|
          charset = f.charset # 文字種別を取得
          f.read # htmlを読み込んで変数htmlに渡す
        end
        # htmlをパース(解析)してオブジェクトを作成
        return Nokogiri::HTML.parse(html, nil, charset)
      end
    
      def GetURLList(url)
        url_list = Array.new
        doc = GetHtmlObj(url)
        doc.css('div[class = "ui-pagination-navi util-left"]>a').each do |page|
          url_list << page.attribute("href").text 
        end
        url_list = url_list.sort_by do |k|
          /(.+)(page=)([\d]+)/ =~ k
          $3.to_i
        end
        return url_list.uniq
      end
    
      def GetURLListAll(url,n)
        url_list_all = Array.new
        crawl_url = URLList.new
        last_url = url
    
        n.times do |n|
          url_list = crawl_url.GetURLList(last_url)
          last_url = url_list.last
    
          url_list_all.concat(url_list)
        end    
         url_list_all = url_list_all.sort_by do |k|
          /(.+)(page=)([\d]+)/ =~ k
          $3.to_i
        end
        return url_list_all.uniq
      end
    
      def GetProductURLList2(url)
        url_list = Array.new
        doc = GetHtmlObj(url)
        doc.css('a[class = "history-item product "]').each do |page|
          url_list << page.attribute("href").text 
        end
    
        return url_list
      end
    
      def GetProductURLList(url)
        url_list = Array.new
        doc = GetHtmlObj(url)
        num=0
        doc.css('a[class ^= "history"]').each do |page|
          puts page
          puts num = num+1
          url_list << page.text 
        end
    
        return url_list
      end
    
      def GetProductURLListAll(url,n)
        url_list = Array.new
        GetURLListAll(url,n).each do |url_tmp|
          doc = GetHtmlObj(url_tmp)
          doc.css('a[class = "history-item product "]').each do |page|
            url_list << page.attribute("href").text 
          end
        end
        return url_list
      end
    
     end
    
    # スクレイピング先のURL
    
    class HtmlObjs
      def GetHtmlObj(init_url, n)
        obj = URLList.new
        urls = obj.GetURLListAll(init_url, n)
    
        htmls = Array.new
        Anemone.crawl(urls, :depth_limit => 0, :delay => 1) do |anemone|
              anemone.on_every_page do |page|
                htmls << page.doc
              end 
        end
    
        return htmls
      end
    
      def GetProductHtmlObj(init_url,n)
        obj = URLList.new
        urls = obj.GetProductURLListAll(init_url,n)
    
        htmls = Array.new
        Anemone.crawl(urls, :depth_limit => 0, :delay => 1) do |anemone|
              anemone.on_every_page do |page|
                htmls << page.doc
              end 
        end
    
        return htmls
      end
    
    end
    
    class ProductInfo
      def GetProductName(html)
        return html.css("h1[class='product-name']").text
      end
    end
    
    
    init_url = "http://ja.aliexpress.com/wholesale?catId=0&initiative_id=AS_20151205231131&SearchText=bag+mens"
    #obj = URLList.new
    #puts urls = obj.GetProductURLListAll(init_url,1)
    
    
    
    #product = ProductInfo.new
    
    
    #htmls = HtmlObjs.new
    #html_list = htmls.GetProductHtmlObj(init_url,1)
    
    
    obj = URLList.new
    
    urllist = obj.GetProductURLList(init_url)
    
    #puts urllist
    
    
    
    #たまにログイン認証画面を取得してしまう
    #商品が36あるはずが、4しか取得できない
    
[/code]


CC BY-SA 3.0
2015-12-06T09:00:19.443
19681
2015-12-07T21:48:51.387
2015-12-07T14:30:12.410
13551
13551
question
ruby web-scraping
nokogiriで取得したいオブジェクトをすべて取得できない


`product-name`ではなく`product`なら似たような状態を再現できました。

[code]

    require 'open-uri'
    require 'nokogiri'
    
    url = 'http://ja.aliexpress.com/wholesale?catId=0&initi'
    doc = Nokogiri::HTML(open(url))
    doc.css('.product').count
    #=> 3
    
[/code]

JSでページを読みこんでるのか, Seleniumを使ったら取得できました。

[code]

    require 'selenium-webdriver'
    require 'nokogiri'
    
    driver = Selenium::WebDriver.for(:firefox)
    driver.navigate.to(url)
    doc = Nokogiri::HTML(driver.page_source)
    doc.css('.product').count
    #=> 36
    
[/code]


CC BY-SA 3.0
2015-12-06T14:19:15.257
19688
2015-12-06T14:19:15.257
3271
19681
answer


ironsandさんも書いているとおり、JavaScriptでページを動的に書き換えているため、静的なHTMLをパースしても求めている結果は得られないようです。

静的なHTMLをパースすると`a[class ^= "history"]`は4件でした。

参考： <https://jsfiddle.net/c9ktnhe5/>

一方、JSが書き換えたあとは40件でした。

参考： <https://jsfiddle.net/c9ktnhe5/1/>

というわけで、これまたironsandさんと同じ回答になりますが、selenium-
webdriver（つまり実際のブラウザ）を使って確認するのが良さそうです。

[code]

    require 'selenium-webdriver'
    require 'nokogiri'
    
    driver = Selenium::WebDriver.for(:firefox)
    url = 'http://ja.aliexpress.com/wholesale?catId=0&initiative_id=AS_20151205231131&SearchText=bag+mens'
    driver.navigate.to(url)
    doc = Nokogiri::HTML(driver.page_source)
    elements = doc.css('a[class^=history]')
    
    texts = elements.map(&:text)
    
    puts elements.size
    puts '=' * 20
    puts texts
    
    driver.quit
    
[/code]

実行結果は以下のようになりました。

[code]

    40
    ====================
    100％手- 織ファッションジュエリー多層ラップレザー編みこみのロープ・男性ブレスレットリストバンドの女性のための腕輪
    溶岩石オニキスビーズターコイズ黒黄金の仏像仏のブレスレットブレスレットの男性女性ヨガファッションジュエリーcs16pulseras女性のアクセサリー
    Uv400標準高- 定義抗疲労tacメガネ、 ステンレス鋼のブランドデザイナーサングラスの男性偏光アビエータードライバ
    新しい熱い販売のスケルトン2015中空機械的な手の風の男性の高級ファッションビジネス革ストラップの腕時計の男性
    ファッションローマンメンズエレガントな革ブラックダイヤルの腕時計アナログクオーツ腕時計安い腕時計男性0675スポーツ
    意志のあるところには道がある手作りアンカー無限大舵多層不織布の女性の魅力のブレスレットの男性のブレスレット
    ジュネーブ時計男性ブランドファッションクォーツ時計スポーツカジュアルドレス学生腕時計腕時計ミリタリークロックrelogiomasculino
    ファッションジュエリーlow0172lbpu革の魅力の友情のブレスレットの腕輪・フェザーアクセサリー結婚式男性のジュエリー送料無料
    編組ワックスコードリストバンド手作りフクロウ愛アンカー空腹ゲーム・ブレスレット革の魅力の腕輪2015の男性のジュエリー
    ブレスレットsttretchpuレザーチャームブレスレット・バングル、 男性ジュエリービジュー象pulseirafemininaァムブレスレットと女性のアクセサリー
    勝者ブランド男性メカニカル ハンド風腕時計クラシック ファッション カジュアル腕時計中空スケルトン レザーストラップレロジオ masculino
    新しい ファッション スポーツ男性夏ミラー サングラス女性ブランド デザイン ビッグ フレーム統合アイウェア の サングラス oculos デゾル uv400
    6 ミリメートル天然白檀仏教仏瞑想108 ビーズ祈り ビーズマラ ブレスレット女性男性ジュエリー
    タングステンメンズブレスレット磁気ヘマタイト8.2" b1372
    最新ファッション販売のホット201516色二重丸多層チャームブレスレット革ブレスレットの男性・女性ギフトブレスレット
    10個木材ビーズの魅力のブレスレット弾性女性調整可能なバングルのブレスレットの宝石のカフの男性卸売ドロップ自由ミックスロット
    韓国人男性のファッションの新しい2015カジュアルショルダー便利な旅行の荷物袋の男の大きなキャンバスのハンドバッグ本物の男性はバッグを旅行
    重い23cm*18mm幅のステンレススティールブレスレットの男性のバイカー自転車オートバイ・チェーンのメンズブレスレットメンズブレスレットの腕輪
    weide2015新しいブランドの男性の高級ファッション時計メンズクォーツアナログデジタルアワー主導のスポーツウォッチは男性軍軍の第二次世界大戦
    Aofly サングラス偏光アルミ マグネシウム スポーツ男性コーティング ミラー駆動サングラス oculos男性アイウェアアクセサリー 8002
    サーモンシャークシリーズステンレス鋼日本ムーブメントケース黒赤ダイヤルラバーバンド男性のカジュアルスポーツクォーツ軍用時計/sh172
    2015 ファッション熱い販売トレンディ シリコン ブレスレット バン グル ジュエリー女性/子供/男性チャーム ブレスレット健康な エネルギー
    熱い販売の新しいファッション2015イタリア高級ブランドステンレス鋼ジュエリー316lモノグラム/ダミエ女性や男性の革のブランドのハンドバッグ
    アナログweideledデジタル腕時計男性用の多機能アラーム日付石英ミリタリーウォッチフルブラックステンレス鋼16ミリメートル
    珍しいスリムな木製時計男性! 珍しいスリムなbewellブランド木製ウォッチムーブメント時計男性vj32木製製品alibabaの熱い女性
    送料無料ファッションヴィンテージアンカーフック無限大人工皮革のブレスレット、 男性・女性ブレスレットの腕輪の宝石
    仏ビーズのブレスレットバングルチャームブレスレット天然石のジュエリー女性と男性のための溶岩pulseiras2015chiusure
    アルミニウムマグネシウムのサングラスの男性偏光スポーツサングラスコーティングミラー駆動oculos6588、 男性眼鏡アクセサリー
    ステンレス鋼黒スケルトンダイヤルゴールドケースブラックレザーストラップクロック手の風のメンズ機械式腕時計カジュアル男性用/pmw197
    新しいファッション2015トムフォードサングラスデザイナー熱い男性と女性のためのボックス付きサングラス
    タイガーアイブレスレットの腕輪ブランドが大好きです仏弾性ロープチェーン天然石ブレスレット女性と男性のためのクリスマスのギフトジュエリー
    アルミニウムマグネシウム2015veithdia自由幸せの男性偏光スポーツサングラスミラードライビングサングラスoculosドゾル126femininoを行う
    手作りのラップレザーブレスレットメンズ本物の本当の友情・2015の女性のための腕輪bileklikpulseiraドcouromasculinaァム
    優れた売れ筋クラシックゴールドクオーツステンレス鋼の腕時計の男性と女性のためのzh3
    送料無料の男性のトラベルバッグ大容量の荷物のハンドバッグ女性に大きくn4141414ビジネスバッグ
    ホット 2015 ファッション メンズ uv400偏光コーティング サングラス男性運転ミラー oculos眼鏡サングラス男で ケース ボックス
    女性ブランドのデザイナーサングラス線oculosカエルミラーサングラス男性レトロサングラスgafasdesol高品質で安い
    するように乗るライブブレスレットsttretchpulseras男性ブレスレット男性の本革のブレスレットの男性・女性のブレスレットの腕輪
    2015オリジナルブランドサングラスファッション色合いオス男性の眼鏡アイウェアサングラス黒コーティングポイント日野外新しいサングラス
    ヴィンテージ手作り新2016パンク釣り針チャームオムの男性のための本革のブレスレットの宝石のアクセサリーの卸売
    
[/code]

## 回答2

CapybaraとPoltergeistというgemを使うとブラウザ（Firefox）を起動せずに同じことを実現できます。  
ただし、Poltergeistを使う場合はFirefoxの代わりにPhantomJSというツール（ヘッドレスブラウザ）をインストールする必要があります。

[code]

    require 'nokogiri'
    require 'capybara'
    require 'capybara/poltergeist'
    
    Capybara.javascript_driver = :poltergeist
    session = Capybara::Session.new(:poltergeist)
    url = 'http://ja.aliexpress.com/wholesale?catId=0&initiative_id=AS_20151205231131&SearchText=bag+mens'
    session.visit url
    doc = Nokogiri::HTML.parse(session.html)
    
    elements = doc.css('a[class^=history]')
    
    texts = elements.map(&:text)
    
    puts elements.size
    puts '=' * 20
    puts texts
    
[/code]


CC BY-SA 3.0
2015-12-07T20:51:38.413
19737
2015-12-07T21:48:51.387
2015-12-07T21:48:51.387
85
85
19681
answer