2011-03-22 70 views
12

將多個請求自動化到網頁搜索表單我試圖學習如何使用RCurl(或者其他合適的R包,如果我錯誤地將RCurl作爲正確的工具)來自動執行提交過程將術語搜索到Web表單並將搜索結果放入數據文件中。我正在處理的具體問題如下:如何使用R

我有一個數據文件給幾輛汽車的車牌號碼(LPN)和車輛識別號碼(VIN)。加利福尼亞州汽車部門(DMV)有一個網頁搜索表格,您可以在此輸入LPN和VIN的最後五位數字,並返回2010年或2009年的車輛牌照費(VLF)付款(有一個選擇器在輸入表單上也是如此)。 (供參考:這是一個研究項目,瞭解VLF支付按車型,型號和車型年份分配)

我可以通過手動輸入每輛車的數據,然後手動輸入結果到電子表格中。但這是21世紀,我想嘗試使這個過程自動化。我想編寫一個腳本,將每個LPN和VIN提交給DMV Web窗體,然後將結果(VLF支付)放入我的數據文件中的一個新的VLF變量中,重複執行此操作直至到達列表的末尾LPN和VINs。 (DMV web表單在這裏順便提一下: https://www.dmv.ca.gov/FeeCalculatorWeb/vlfForm.do)。

我的計劃是使用getHTMLFormDescription()(在RHTMLForms包中)來查找輸入字段的名稱,然後使用getForm()或postForm()(在RCurl包中)來檢索輸出。不幸的是,我陷入了第一步。下面是我用R命令和輸出:

> forms = getHTMLFormDescription("https://www.dmv.ca.gov/FeeCalculatorWeb/vlfForm.do") 
Error in htmlParse(url, ...) : 
    File https://www.dmv.ca.gov/FeeCalculatorWeb/vlfForm.do does not exist 

不幸的是,是相對較新的R和幾乎完全新的HTTP和網絡刮,我不知道下一步該怎麼做。

首先,有沒有人知道爲什麼我在getHTMLFormDescription()調用中遇到錯誤?或者,是否有另一種方法來確定輸入字段的名稱?第二,你能否建議一些示例代碼來幫助我開始實際提交LPN和VIN並檢索輸出結果? getForm()或postForm()是正確的方法還是應該做其他事情?如果這將有助於有一些真正的LPN-VIN組合提交,這裏有三個:
LPN VIN
5MXH018 30135
4TOL562 74735
5CWR968 11802

最後,因爲你可以看到我是一個完整的新手,你有什麼我需要學習的建議,以便熟練這種網頁抓取,以及如何去學習它(使用R或其他語言)?對網站,書籍,listservs,其他StackOverflow問題等的具體建議會很好。

感謝您的幫助。

+1

快速提示:爲firefox安裝firebug並使用網絡選項卡查看發佈的表單實際上是通過網線發送的。 – Spacedman 2011-03-22 19:37:48

+1

該頁面給我一個錯誤消息,上面的代碼。但提示:檢查通過'http://www.dmv.ca.gov/wasapp/FeeCalculatorWeb/vlfFees.do方法= calculateVlf&提交=確定%20VLF&vehicleLicense = 5CWR968&vehicleTaxYear = 2010&vehicleVin = 11802' – daroczig 2011-03-22 23:52:37

+1

@daroczig謝謝!爲了將來的參考,一個人怎麼看出來?另外,如果我使用您提供的url和getURL(url),它將返回給出我想要輸出的頁面的html。你能否提出一個關於如何使用R從html混亂中選擇所需文本(在這種情況下,支付金額的值)的好教程(是的,我確實是全新的)? – eipi10 2011-03-23 17:13:18

回答

5

添加到由daroczig和Rguy建議,這裏是一個短的一段代碼來自動將數據提取到的數據幀的整個過程。

# construct sample data frame with lpn, vpn and years 
lpn = rep(c('5MXH018', '4TOL562', '5CWR968'), 2); 
vpn = rep(c('30135', '74735', '11802'), 2); 
year = c(rep(2009, 3), rep(2010, 3)); 
mydf = data.frame(lpn, vpn, year); 

# construct function to extract data for one record 
get_data = function(df){ 

    library(XML); 
    # root url 
    root = 'http://www.dmv.ca.gov/wasapp/FeeCalculatorWeb/vlfFees.do?method=calculateVlf&su%C2%ADbmit=Determine%20VLF' 

    # construct url by adding lpn, year and vpn 
    u = paste(root, '&vehicleLicense=', df$lpn, '&vehicleTaxYear=', 
      df$year, '&vehicleVin=', 
     df$vpn, sep = ""); 

    # encode url correctly 
    url = URLencode(u); 

    # extract data from the right table 
    data = readHTMLTable(url)[[5]]; 

} 

# apply function to every row of mydf and return data frame of results 
library(plyr) 
mydata = adply(mydf, 1, get_data); 

# remove junk from column names 
names(mydata) = gsub(':\302\240\302\240', '', names(mydata)) 
+0

很好的答案(+1)!這個頁面越來越令人興奮,超鏈接遍佈答案:)如果你讓我給你寫一些小補充答案:分號在末尾不需要(不像在PHP中),在你的函數中,你應該''返回'數據'和一個'sys.sleep'函數應該在'get_data'函數結束時被調用,而不是很麻煩服務器。 – daroczig 2011-03-24 08:12:24

+0

@Ranmath:感謝您花時間編寫此腳本。這非常有幫助。我已經選擇它作爲最佳答案。後續問題:您(或@daroczig或任何其他人)是否對良好的網站,書籍等有足夠的關於R,HTTP,HTML和正則表達式的學習,可以爲任何網頁抓取任務?哦,你能解釋一下gsub電話裏的內容嗎?再次感謝。 – eipi10 2011-03-24 15:36:19

+0

的GSUB調用內部的東西,只是刪除了術語「:\ 302 \ 240 \ 302 \ 240」從列名從 – Ramnath 2011-03-24 17:00:24

4

只需使用http而不是https並且應該可以解決您的問題。下面是輸出,如果你嘗試這種

forms = getHTMLFormDescription("http://www.dmv.ca.gov/wasapp/FeeCalculatorWeb/vlfForm.do", 
    dropButtons = TRUE) 

[[1]] HTML表單你:http://search.ca.gov/search 問:[搜索DMV網站]

$ feeRequestForm HTML表單:http://www.dmv.ca.gov/wasapp/FeeCalculatorWeb/vlfFees.do vehicleLicense: ]
vehicleTaxYear: vehicleVin:[]

下面是如何填寫表格,並從雅虎體育頁面獲取數據表的例子。

# get form description 
url = 'http://ca.sports.yahoo.com/nhl/stats/byteam?cat=teamstats&sort=404' 
forms = getHTMLFormDescription(url); 

# create a function using form description, to query the url 
efun = createFunction(forms[[3]]); 

# extract webpage by passing required arguments to function 
page = efun(year = 'season_2009', conference = 'Eastern'); 

# parse webpage and return html tree 
doc = htmlTreeParse(page, asText = T, useInternalNodes = T); 

# extract table from the html tree 
tab = readHTMLTable(doc); 

我申請這個到您指定的網頁,但由於某些原因的表單元素返回VehicleTaxYear錯誤導致的錯誤。有更深入的HTML表單知識的人可以指導你如何調試這個錯誤。

希望這是有用的

編輯。我修正了一個錯誤。它應該是createFunction(forms[[3]]),因爲我們只對第三種形式感興趣。

+1

@Ranmath我試過這個,但得到了以下錯誤:'> efun = createFunction(forms) writeFunction中的錯誤(formDescription,character(),url,con,verbose = verbose,: 您應該在這裏提供一個表單描述。 getFormDescription()。」此外,它看起來像你的‘createFunction(efun)’應該是‘createFunction(形式)’,但我甚至做的是修正後得到一個錯誤。不知道如何解決這個問題?謝謝。 – eipi10 2011-03-23 17:01:02

+0

看到我的編輯。它應該解決這個問題。它仍然不能解決你的網頁的問題,但可能是有用的。 – Ramnath 2011-03-23 20:41:19

2

我打算在原帖之後發表評論,但沒有足夠的聲望。

我用@daroczig提供,以獲得想要eipi10通過執行以下操作中的實際數據的網址:

datas <- readHTMLTable("http://www.dmv.ca.gov/wasapp/FeeCalculatorWeb/vlfFees.do?method=calculateVlf&su%C2%ADbmit=Determine%20VLF&vehicleLicense=5CWR968&vehicleTaxYear=2010&vehicleVin=11802") 
processed <- datas[[5]][[1]] 
paid <- datas[[5]][[2]] 
refund <- datas[[5]][[3]] 

總之,readHTMLTable命令是用於格式化HTML代碼是有用的。
我第二eipi10的請求如何daroczig獲得的網址。

+1

很好的答案(+1)!我做了以下有關獲取URL細節的答案。 – daroczig 2011-03-23 21:10:25

3

我上面的評論的細節:

  • 火了火狐Firebug :)
  • 填寫表格與一對所需的印版沒有的。然後點擊提交(「確定VLF」)
  • 點擊Firebug中的「Net」選項卡,並檢查發送給服務器的請求,比如(對不起,匈牙利用戶界面 - 但你會得到我希望的):

enter image description here

  • 你可以看到一個POST請求被髮送,但數據可以通過GET請求還可以達到,在「POST vlfFees.do」所以只需右擊並選擇「複製包含所有參數的網址「,並通過獲取所需的網址完成。
  • 您可以用簡單的URL所需的LPN和VIN修改URL(vehicleLicensevehicleVin後)
  • 並調用與readHTMLTableXML包修改後的URL將提供你所需要的數據集的一個很好的數據幀。

所以:

library(XML) 
datas <- readHTMLTable("http://www.dmv.ca.gov/wasapp/FeeCalculatorWeb/vlfFees.do?method=calculateVlf&su%C2%ADbmit=Determine%20VLF&vehicleLicense=5CWR968&vehicleTaxYear=2010&vehicleVin=11802") 

,並獲得表的所需值@Rguy以上建議:

processed <- datas[[5]][[1]] 
paid <- datas[[5]][[2]] 
refund <- datas[[5]][[3]] 

有了這個基本的例子,你可以很容易地寫一個循環中獲取所有所需數據,但不要貪和不循環,而不睡眠調用(請參閱:Sys.sleep)。我每分鐘只能獲取一塊板,這絕對不會影響服務器。