2016-12-27 105 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