2016-12-27 41 views
4

问题:可靠刮股价表

我的目标是自动从本网站stock prices抓取与货币的价格表。由于股票经纪人未提供API,我不得不寻找解决办法。

为了避免重复发明轮子和浪费时间/金钱,我已经为此寻找申请,但不幸的是我没有找到一个适用于本网站的申请。

我已经试过:

  1. Rrvest

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) 

获取一个空表。

  • JavaScriptcasperJS
  • 这个选项是迄今为止最好的,我居然能提取数据,但它是非常缓慢的,并最终与崩溃“内存耗尽” 错误:

    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"); 
    
  • JavaSciptPhantomJS
  • 使用此选项我只得到一个单一的表中:

    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'); 
    
        }); 
    }); 
    
  • PythonBeautifulSoup
  • 获得一个空表的结果:

    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

    尝试与“Scrapy壳牌”,但得到了一张空表。

  • Pandas和它的read_html()
  • 随着pandas我有以下错误:

    ValueError: No tables found matching pattern '.+'

    的代码:

    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. 什么是最可靠的方式来处理这个特定的股票价格网站的网络抓取?

    注:这可能是该网站正试图阻止网络刮,我研究robots.txt,但它看起来像有只通过浏览器支持的具体和谷歌机器人的具体说明。

    +0

    尝试用Python'selenium'编号:http://selenium-python.readthedocs.io/installation.html – Prabhakar

    +0

    尝试用Scrapy +飞溅蟒蛇。 @Prabhakar硒很好,但速度太慢。 – parik

    +0

    另外python + pandas''read_html'很好。 http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_html.html –

    回答

    6

    主要的问题是,这个特定的网站是相当动态 - 加载表是与您的浏览器将额外的XHR请求异步完成。

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

    现在,随着中说,由于该资源没有可用的公共API,你基本上有两个常规选项,姑且称之为“低级”和“高级”:

    1. “低级别”。使用浏览器开发工具,检查表格是如何加载的,并在代码中模拟相同的请求 - 例如使用requests

    2. “高级”。其实自动化一个真实的浏览器与例如,selenium。该选项类似于您的casperJSphantomJS方法,但您必须考虑“等待要加载的元素”等特定内容 - 给浏览器加载页面和表格的时间。

    让我们专注于第二种方法。通过pip安装selenium

    pip install selenium 
    

    让我们使用Chrome(你也可以使用FirefoxPhantomJS或其他人也)。假设您已安装实际浏览器,请下载适用于Windows的最新chromedriver。通过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 
    

    请注意,你不必做HTML解析和数据提取与pandas - 一旦你在driver.page_source HTML源代码,您已经做了最复杂的部分。然后,您可以使用任何您喜欢的工具 - 受欢迎的选项是BeautifulSouplxml.html。从性能的角度来看,后者将是一个不错的选择。


    作为一个侧面说明,做网络刮的时候,你应该总是试图成为一个良好的网络刮公民留在法律方面 - 遵守该服务的“使用条款”,尊重“robots.txt”规则,不要过于频繁地访问网站和/或通过提供特定的“User-Agent”标题或联系资源所有者或维护人员了解获取所需数据的最佳方式来标识自己。相关资源:

    -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