如何使用R自动化对Web搜索表单的多个请求

时间:2011-03-22 19:02:47

标签: r web-scraping

我正在尝试学习如何使用RCurl(或其他合适的R包,如果我错误地认为RCurl是正确的工具)来自动化将搜索词提交到Web表单并将搜索结果放入的过程一个数据文件。我正在处理的具体问题如下:

我有一个数据文件,给出了几辆汽车的车牌号码(LPN)和车辆识别号码(VIN)。加州汽车部门(DMV)有一个网页搜索表单,您可以在其中输入LPN和VIN的最后五位数字,并返回2010年或2009年的车辆牌照费(VLF)付款(有一个选择器)在输入表格上也是如此)。 (仅供参考:这是一个研究项目,用于查看车辆制造,型号和型号年份的VLF支付分布)

我可以完成为每辆车手动输入数据的繁琐过程,然后手动将结果输入电子表格。但这是21世纪,我想尝试自动化这个过程。我想编写一个脚本,将每个LPN和VIN提交到DMV Web表单,然后将结果(VLF支付)放入我的数据文件中的新VLF变量中,重复执行此操作直到它到达列表末尾LPN和VIN。 (顺便说一句,DMV网络表格在这里: 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或用另一种语言)?对网站,书籍,列表服务器,其他StackOverflow问题等的具体建议会很棒。

感谢您的帮助。

4 个答案:

答案 0 :(得分: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))

答案 1 :(得分: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表单有更深入了解的人将能够指导您如何调试此错误。

希望这很有用

EDIT。我修正了一个错误。它应该是createFunction(forms[[3]]),因为我们只对第三种形式感兴趣。

答案 2 :(得分:4)

上述评论的详细信息:

  • 使用Firebug启动Firefox:)
  • 用一对所需的盘子填写表格。等等,然后单击“提交”(“确定VLF”)
  • 单击Firebug中的“Net”选项卡并检查发送到服务器的请求,例如(对不起,匈牙利用户界面 - 但您会得到我希望的观点):

enter image description here

  • 您可以看到发送了POST请求,但也可以通过GET请求访问数据,因此只需右键单击“POST vlfFees.do”并选择“使用所有参数复制URL”即可完成通过获取所需的URL。
  • 您可以简单地在网址中修改所需的LPN和VIN的网址(在vehicleLicensevehicleVin之后),
  • 只需使用XML包中的readHTMLTable调用修改后的网址,即可为您提供所需数据集的精彩数据框。

所以:

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)。我每分钟只能拿一个盘子,这肯定不会打扰服务器。

答案 3 :(得分:2)

我打算在原帖后发表此评论,但声誉不足。

我使用了@daroczig提供的URL,通过执行以下操作来获取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如何获得网址的请求。