Как ни странно, ни основной сайт, ни провайдер, которого они используют для поиска торговых точек, не предотвращают очистку T&C или REP. ¯\_(ツ)_/¯
Вам действительно следует ознакомиться с инструментами разработчика браузера, поскольку вы могли бы видеть, что основной сайт делает POST
HTTP-запрос к сайту поиска, а не 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
res
- это объект httr
response
, и обычно можно просто сделать:
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()
и немного поработать, чтобы привести данные в подходящую форму для создания фрейма данных. Это очень хрупкий код в том смысле, что этот конкретный фрагмент может обрабатывать отсутствующие данные о номере телефона, но не более того. Если есть вторая адресная строка, вам нужно изменить этот подход или использовать другой подход:
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
столбцу
- объединить весь текст в одну строку, каждая часть разделена
|
- отделить все отдельные биты
Надеюсь, это поможет объяснить хрупкость.
Конечно, вам нужна была только часть «как добраться до контента», но, надеюсь, это сэкономит вам немного времени.
person
hrbrmstr
schedule
14.10.2017