Подтвердить что ты не робот

Как автоматизировать несколько запросов в форме веб-поиска, используя R

Я пытаюсь узнать, как использовать RCURL (или какой-либо другой подходящий R-пакет, если я ошибаюсь, когда RCURL является правильным инструментом), чтобы автоматизировать процесс отправки поисковых запросов в веб-форму и размещение результатов поиска в файл данных. Конкретная проблема, над которой я работаю, такова:

У меня есть файл данных с номером номерного знака (LPN) и идентификационным номером автомобиля (VIN) для нескольких автомобилей. Калифорнийский департамент автотранспортных средств (DMV) имеет форму поиска по веб-странице, в которой вы вводите LPN и последние пять цифр VIN, и он возвращает плату за лицензионный сбор за автомобиль (VLF) за 2010 или 2009 год (там есть селектор для что и на входной форме). (FYI: Это для исследовательского проекта, чтобы посмотреть на распределение платежей VLF по марке автомобиля, модели и модельному году)

Я мог бы пройти через утомительный процесс ручного ввода данных для каждого автомобиля, а затем вручную ввести результат в электронную таблицу. Но это 21-й век, и я хотел бы попытаться автоматизировать процесс. Я хочу написать script, который будет передавать каждый LPN и VIN в веб-форму DMV, а затем поместить результат (платеж 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 и т.д. Были бы замечательными.

Спасибо за вашу помощь.

4b9b3361

Ответ 1

Добавляя к предложению 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))

Ответ 2

Просто используйте http вместо https, и это должно решить вашу проблему. Вот результат, который вы получите, если попробуете этот

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

[[1]] Форма HTML: http://search.ca.gov/search q: [Поиск сайта DMV]

$feeRequestForm Форма HTML: http://www.dmv.ca.gov/wasapp/FeeCalculatorWeb/vlfFees.do vehicleLicense: []
vehicleTaxYear: vehicleVin: []

Вот пример того, как заполнить форму и получить таблицу данных с спортивной страницы yahoo.

# 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]]), так как нас интересует только третья форма.

Ответ 3

Детали моего комментария выше:

  • Запустите Firefox с помощью Firebug:)
  • Заполните форму одной парой нужной пластины. и так, и нажмите submit ( "Определить VLF" )
  • Перейдите на вкладку "Net" в Firebug и проверьте отправленный запрос на сервер, например (извините, венгерский пользовательский интерфейс), но вы получите то, что я надеюсь):

enter image description here

  • Вы можете увидеть, что был отправлен запрос POST, но данные также могут быть получены с помощью запроса GET, поэтому просто щелкните правой кнопкой мыши по "POST vlfFees.do" и выберите "Копировать URL со всеми параметрами", и все готово путем получения требуемого URL-адреса.
  • Вы можете изменить URL с нужной LPN и VIN в URL просто (после vehicleLicense и vehicleVin),
  • И просто назовите измененный URL с readHTMLTable из XML, который предоставит вам хороший кадр данных требуемого набора данных.

Итак:

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). Я бы получил только одну пластину в минуту или около того, что, безусловно, не сильно беспокоило бы сервер.

Ответ 4

Я хотел опубликовать это как комментарий после оригинального сообщения, но не имел достаточной репутации.

Я использовал URL-адрес, который @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 получил URL.