2017-10-14 123 views
0

我正在嘗試使用rvest來掃描在cgi-bin中彈出的webform的結果。但是,當我運行該腳本時,我會在200英里內返回0個結果。以下是我的代碼,我感謝任何反饋和幫助。主要網站是http://www.zmax.com/,它具有啓動cgi-bin的搜索框。我該如何用rvest和R刮一個CGI-Bin?

library(rvest); 
library(purrr) ; 
library(plyr) ; 
library(dplyr) ; 

x<-read_html('http://www.nearestoutlet.com/cgi-bin/smi/findsmi.pl') 

y<-x%>% html_node('table')%>% html_table(fill=true) 

我也試過

y<-x%>% 
html_node('td div td, p') 
%>% html_text() 

我不確定我在哪裏在返回那是表單上的數據會錯的。

回答

0

奇怪的是,他們用於出口查找的主站點和提供者都不會阻止C或REP進行搜索。 ¯\_(ツ)_/¯

你真的應該熟悉的瀏覽器開發者工具,你就已經能夠看出,主站點發出HTTP POST請求查找網站的VS要求GET瀏覽器通常讓那read_html()做。這裏有您需要做什麼才能獲得成功請求(我們會選擇一個郵政編碼近十歲上下的你):

library(httr) 
library(rvest) 

POST(
    url = "http://www.nearestoutlet.com/cgi-bin/smi/findsmi.pl", 
    body = list(zipcode = "48127"), 
    encode = "form" 
) -> res 

reshttrresponse對象和一個會通常只是做:

content(res, as="parsed") 

得到一個解析對象準備XML/HTML解析。但是,有奇怪的編碼問題(至少對我來說),在該網站上迫使我們必須做的:

content(res, as="raw") %>% read_html() -> pg 

您應該cat(as.character(pg))看看HTML是如何醜陋。它是嵌套表格,但不是一個好方法。您看到的條目全部爲<tr>元素,沒有<table>中斷。值得慶幸的是?在這些<tr>元素的每一箇中只有單個的<td>元素。因此,我們可以通過瞄準正確的<table>抓住他們所有一舉:

rows <- html_nodes(pg, "table[width='300'] > tr > td") 
rows 
## {xml_nodeset (60)} 
## [1] <td width="300" height="19" bgcolor="#8B0101"><p align="left"><font face="Tahoma" color="#FFFFFF" style="font-size: 11px"><b>O\u0092REILLY AUTO PARTS</b></fo ... 
## [2] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px">6938 NORTH TELEGRAPH ROAD</font></td> 
## [3] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px">Dearborn Heights, MI 48127</font></td> 
## [4] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px">(313) 792-9134</font></td> 
## [5] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px"><a href="#" onclick="window.open('http://maps.google.com/maps?q=6938+NORTH+TELEGRAPH+R ... 
## [6] <td width="300" height="6"></td> 
## [7] <td width="300" height="19" bgcolor="#8B0101"><p align="left"><font face="Tahoma" color="#FFFFFF" style="font-size: 11px"><b>Advance Auto Parts</b></font></p ... 
## [8] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px">8120 North Telegraph Road</font></td> 
## [9] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px">Dearborn Heights, MI 48127</font></td> 
## [10] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px">(313) 528-4920</font></td> 
## [11] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px"><a href="#" onclick="window.open('http://maps.google.com/maps?q=8120+North+Telegraph+R ... 
## [12] <td width="300" height="6"></td> 
## [13] <td width="300" height="19" bgcolor="#8B0101"><p align="left"><font face="Tahoma" color="#FFFFFF" style="font-size: 11px"><b>Pep Boys</b></font></p></td> 
## [14] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px">8955 TELEGRAPH RD</font></td> 
## [15] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px">Redford, MI 48239</font></td> 
## [16] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px">(313) 532-5750</font></td> 
## [17] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px"><a href="#" onclick="window.open('http://maps.google.com/maps?q=8955+TELEGRAPH+RD+Redf ... 
## [18] <td width="300" height="6"></td> 
## [19] <td width="300" height="19" bgcolor="#8B0101"><p align="left"><font face="Tahoma" color="#FFFFFF" style="font-size: 11px"><b>O\u0092REILLY AUTO PARTS</b></fo ... 
## [20] <td width="300" height="2"><font face="Tahoma" style="font-size: 11px">27207 PLYMOUTH ROAD</font></td> 
## ... 

許多接近一個可能需要做一個數據幀的是混亂的。一個簡單的方法就是使用商店標題具有設置背景色的事實,而其他人則不會。這使得代碼有點脆弱,但是通過測試背景顏色的存在,我們可以幫助它變得更加脆弱。爲什麼我們甚至需要這樣做?那麼,我們需要標記記錄的開始和結束,一個簡單的方法就是使用這樣一個事實,即我們可以知道cumsum()是一個邏輯向量FALSE == 0.爲什麼這很重要?我們可以創建一個隱含的分組列這樣:

data_frame(
    record = !is.na(html_attr(rows, "bgcolor")), 
    text = html_text(rows, trim=TRUE) 
) %>% 
    mutate(record = cumsum(record)) -> xdf 
#3 # A tibble: 60 x 2 
#3 record      text 
#3  <int>      <chr> 
#3 1  1 "O\u0092REILLY AUTO PARTS" 
#3 2  1 6938 NORTH TELEGRAPH ROAD 
#3 3  1 Dearborn Heights, MI 48127 
#3 4  1    (313) 792-9134 
#3 5  1    0 miles away 
#3 6  1        
#3 7  2   Advance Auto Parts 
#3 8  2 8120 North Telegraph Road 
#3 9  2 Dearborn Heights, MI 48127 
#3 10  2    (313) 528-4920 
#3 # ... with 50 more rows 

現在,我們需要與filter()刪除空行,並做一些改寫(munging)獲取數據到一個像樣的形式製作的數據幀。這是超級脆弱代碼,因爲這個特定的片段可以處理丟失的電話號碼數據,但這就是它。如果有第二個地址線,你需要修改這個方法,或者使用不同的方法:

filter(xdf, text != "") %>% 
    group_by(record) %>% 
    summarise(x = paste0(text, collapse="|")) %>% 
    separate(x, c("store", "address1", "city_state_zip", "phone_and_or_distance"), sep="\\|", extra="merge") 
## # A tibble: 10 x 5 
## record      store     address1    city_state_zip  phone_and_or_distance 
## * <int>      <chr>      <chr>      <chr>      <chr> 
## 1  1 "O\u0092REILLY AUTO PARTS" 6938 NORTH TELEGRAPH ROAD Dearborn Heights, MI 48127 (313) 792-9134|0 miles away 
## 2  2   Advance Auto Parts 8120 North Telegraph Road Dearborn Heights, MI 48127 (313) 528-4920|0 miles away 
## 3  3     Pep Boys   8955 TELEGRAPH RD   Redford, MI 48239 (313) 532-5750|2 miles away 
## 4  4 "O\u0092REILLY AUTO PARTS"  27207 PLYMOUTH ROAD   Redford, MI 48239 (313) 937-1787|2 miles away 
## 5  5 "O\u0092REILLY AUTO PARTS"  14975 TELEGRAPH ROAD   Redford, MI 48239 (313) 538-3584|2 miles away 
## 6  6     AutoZone   24250 FIVE MILE   Redford, MI 48239 (313) 527-6877|2 miles away 
## 7  7 "O\u0092REILLY AUTO PARTS"  5940 MIDDLEBELT RD  Garden City, MI 48135 (734) 525-1607|3 miles away 
## 8  8     AutoZone  6228 MIDDLEBELT RD  Garden City, MI 48135 (734) 513-2233|3 miles away 
## 9  9   Advance Auto Parts  3845 S Telegraph Rd   Dearborn, MI 48124 (313) 274-6549|3 miles away 
## 10  10 "O\u0092REILLY AUTO PARTS"  27565 MICHIGAN AVENUE   Inkster, MI 48141 (313) 724-8544|3 miles away 

萬一這個過程是不明顯的,我們:

  • 組行通過我們剛創建的record
  • 斯馬什所有文本合併爲一個字符串,將每個部分與|
  • 分離出所有單個比特分開

這可能有助於解釋脆弱性。當然,你只想要「如何到達內容」部分,但希望這會爲你節省更多時間。

+0

哇!對於所有步驟來說,這是多麼美妙的解釋您還教會了我一種更有效的處理嵌套數據的新方法。我一直在處理這樣的數據結構,而這只是清理時間的一小部分。我是否需要從一個循環中打印值,從一系列郵政編碼中運行此問題?通常我只會用列表命名一個對象。 – Turbogoon

+0

如果你可以在一個新問題中做出一個可重複的例子,它會使我和其他人都能夠提供幫助。我很高興,這解決了你的一些問題,壽。 – hrbrmstr

+0

它做的比這更多。數據困難巨大。我在這裏發佈了一個新問題https://stackoverflow.com/questions/46759058/how-to-pass-multiple-values-in-a-rvest-submission-form再次感謝您的幫助。我提高了但是新的我不認爲它做了很多。 – Turbogoon