可靠地刮取股票价格表

时间:2016-12-27 12:06:23

标签: javascript python r selenium web-scraping

问题:

我的目标是使用此网站stock prices的货币价格自动抓取表格。由于股票经纪人不提供API ,我不得不找到解决方法。

我已经为此目的搜索了应用程序,以避免重新发明轮子并浪费时间/金钱,但遗憾的是我没有找到一个可以使用本网站的单一应用程序。

我尝试了什么:

  1. Rrvest
  2. R以其简单和直接的使用而闻名。让我们看看代码,它基本上是来自texbook的复制粘贴示例:

    library("rvest")
    url <- "https://iqoption.com/en/historical-financial-quotes?active_id=1&tz_offset=120&date=2016-12-19-19-0"
    population <- url %>%
      read_html() %>%
      html_nodes(xpath='//*[@id="mCSB_3_container"]/table') %>%
      html_table()
    population
    population <- population[[1]]
    
    head(population)
    

    获得一张空桌子。

    1. JavaScriptcasperJS
    2. 这个选项是迄今为止最好的,我实际上能够提取数据,但它非常慢并且最终因“内存耗尽”错误而崩溃:

      var casper = require('casper').create({
        logLevel:'debug',
        verbose:true,
        loadImages: false,
        loadPlugins: false,
        webSecurityEnabled: false,
        userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11"
      });
      
      var url = 'https://eu.iqoption.com/en/historical-financial-quotes?active_id=1&tz_offset=60&date=2016-12-19-21-0';
      var length;
      var fs = require('fs');
      var sep = ';';
      //var count = 0;
      casper.start(url);
      
      //date
      var today = new Date();
      var dd = today.getDate();
      var mm = today.getMonth()+1; //January is 0!
      var hh = today.getHours();  
      var fff = today.getMilliseconds();  
      var MM = today.getMinutes();
      
      var yyyy = today.getFullYear();
      if(dd<10){
          dd='0'+dd;
      } 
      if(mm<10){
          mm='0'+mm;
      } 
      
      
      var today = yyyy +'_'+mm + '_' +dd + '_'+ hh +'_'+ MM +'_'+ fff;
      casper.echo(today);
      
      function getCellContent(row, cell) {
          cellText = casper.evaluate(function(row, cell) {
              return document.querySelectorAll('table tbody tr')[row].childNodes[cell].innerText.trim();
          }, row, cell);
          return cellText;
      }
      
      function moveNext()
      {
          var rows = casper.evaluate(function() {
              return document.querySelectorAll('table tbody tr');
          });
          length = rows.length;
          this.echo("table length: " + length);
      };
      
      //get 3 tables
      for (var mins = 0; mins < 3; mins++)
      { 
      
          url = 'https://eu.iqoption.com/en/historical-financial-quotes?active_id=1&tz_offset=60&date=2016-12-19-21-' + mins;
      
          casper.echo(url);
          casper.thenOpen(url);
           casper.then(function() {
              this.waitForSelector('#mCSB_3_container table tbody tr');
          }); 
      
          casper.then(moveNext);
      
          casper.then(function() {
          for (var i = 0; i < length; i++) 
          {
              //this.echo("Date: " + getCellContent(i, 0));
              //this.echo("Bid: " + getCellContent(i, 1));
              //this.echo("Ask: " + getCellContent(i, 2));
              //this.echo("Quotes: " + getCellContent(i, 4));
      
              fs.write('prices_'+today+'.csv', getCellContent(i, 0) + sep + getCellContent(i, 1) + sep + getCellContent(i, 2) + sep + getCellContent(i, 4) + "\n", "a");
          }
          });  
      
      
      }
      
      casper.run(); 
      this.echo("finished with processing");
      
      1. JavaSciptPhantomJS
      2. 使用此选项,我只获得一个表:

        var webPage = require('webpage');
        var page = webPage.create();
        
        page.open('https://iqoption.com/en/historical-financial-quotes?active_id=1&tz_offset=120&date=2016-12-19-19-0', function(status) {
        
          var title = page.evaluate(function() {
            return document.querySelectorAll('table tbody tr');
        
          });
        });
        
        1. PythonBeautifulSoup
        2. 获得一张空表:

          from bs4 import BeautifulSoup
          from urllib2 import urlopen
          
          
          url = "https://iqoption.com/en/historical-financial-quotes?active_id=1&tz_offset=120&date=2016-12-19-19-0"
          soup = BeautifulSoup(urlopen(url), "lxml")
          
          table = soup.findAll('table', attrs={ "class" : "quotes-table-result"})
          print("table length is: "+ str(len(table)))
          
          1. Scrapy
          2. 尝试使用“Scrapy Shell”但结果是空桌。<​​/ p>

            1. Pandas,它是read_html()
            2. pandas我收到以下错误:

                

              ValueError:找不到匹配模式'。+'

              的表格

              代码:

              import pandas as pd
              import html5lib
              
              f_states = pd.read_html("https://iqoption.com/en/historical-financial-quotes?active_id=1&tz_offset=120&date=2016-12-19-19-0")
              print f_states
              

              问题:

              1. 请问您解释为什么我在尝试不同的网页抓取和HTML解析工具时会得到空表?
              2. 对这个特定股票价格网站进行网络抓取的最可靠方法是什么?
              3. 注意:可能是该网站正在尝试阻止抓取网页,我已经研究过robots.txt,但看起来只有浏览器支持专用和google-bot特定说明。

2 个答案:

答案 0 :(得分:6)

主要问题是这个特定网站非常动态 - 加载表是与浏览器提出的其他XHR请求异步完成的。

除了使用实际浏览器(casperJSPhantomJS)之外的所有方法都会失败,因为他们只会在没有所有动态部分的情况下下载初始HTML页面 。换句话说,rvesturllib2不是浏览器,也没有内置的JavaScript引擎。

现在,由于没有公共API可用于此资源,因此您基本上有两个常规选项,我们将其称为“低级别”和“高级别”:

  1. “低电平”。使用浏览器开发人员工具,检查表的加载方式并在代码中模拟相同的请求 - 例如,使用requests

  2. “高电平”。实际上自动化一个真正的浏览器,例如,selenium。此选项与您的casperJSphantomJS方法类似,但您必须考虑某些事项,例如“等待加载元素” - 为浏览器提供加载页面和表格的时间。< / p>

  3. 让我们关注第二种方法。通过selenium安装pip

    pip install selenium
    

    我们使用Chrome(您也可以使用FirefoxPhantomJS或其他人)。假设您已安装实际的浏览器,请下载最新的chromedriver for Windows。浏览Getting Started页面,确保其正常运行。

    然后,让我们加载您的网页,等待加载表格(等待通过WebDriverWait和一组预期条件完成)。然后,我们将获取页面源并将其传递给pandas以进行进一步的解析和数据提取(我们也可以通过selenium完成它 - 找到元素并获取它们的文本,但这将是慢 - 记住你的casperJS方法:

    import pandas as pd
    
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    
    url = "https://iqoption.com/en/historical-financial-quotes?active_id=1&tz_offset=120&date=2016-12-19-19-0"
    
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.get(url)
    
    # wait for a table to load
    wait = WebDriverWait(driver, 10)
    wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "#mCSB_3_container table tbody tr")))
    
    # read the page source and pass it to "pandas"
    dfs = pd.read_html(driver.page_source)
    
    # close the browser - we don't need it anymore, it's job is done
    driver.close()
    
    print(dfs)  # dfs is a list of DataFrame instances
    

    请注意,您不必使用pandas进行HTML解析和数据提取 - 一旦您在driver.page_source中拥有HTML源代码,您就完成了最复杂的部分。然后,您可以使用自己熟悉的工具 - 热门选项为BeautifulSouplxml.html。从绩效角度来看,后者将是一个不错的选择。

    作为旁注,在进行网络抓取时,您应该始终努力成为一个良好的网络抓取公民并保持合法的一面 - 遵守服务的“使用条款”,尊重“机器人”。 txt“规则,不要过于频繁地访问网站和/或通过提供特定的”用户代理“标题或与资源所有者或维护者联系以获取所需数据的最佳方式来表明自己。相关资源:

答案 1 :(得分:-1)

你不能简单地使用quantmod吗?

install.packages('quantmod')

则...

> getSymbols("YHOO",src="google") # from google finance 
[1] "YHOO" 
> getSymbols("GOOG",src="yahoo") # from yahoo finance 
[1] "GOOG" 
> getSymbols("DEXJPUS",src="FRED") # FX rates from FRED 
[1] "DEXJPUS" 
> getSymbols("XPT/USD",src="Oanda") # Platinum from Oanda 
[1] "XPTUSD"

每次调用都会导致数据直接加载到您的工作区中,并使用调用返回的对象名称。有点方便,但它会变得更好......

> # Specify lookup parameters, and save for future sessions. 
> 
> setSymbolLookup(YHOO='google',GOOG='yahoo') 
> setSymbolLookup(DEXJPUS='FRED') 
> setSymbolLookup(XPTUSD=list(name="XPT/USD",src="oanda")) 
> saveSymbolLookup(file="mysymbols.rda") 
> # new sessions call loadSymbolLookup(file="mysymbols.rda") 
> 
> getSymbols(c("YHOO","GOOG","DEXJPUS","XPTUSD")) 
[1] "YHOO" "GOOG" "DEXJPUS" "XPTUSD"

有关所有详细信息,请参阅此链接。

http://www.quantmod.com/examples/intro/#data