戳了 robots.txt 和条款和常见问题页面,找不到任何禁止抓取的内容。如果有人这样做,请发表评论,我很乐意删除答案。
有时您不能只获取 URL,尤其是当需要发出 POST 请求时(这里就是这种情况)。这就是curlconverter 出现的地方。右键单击“开发工具”视图中的表格条目,选择“复制为 cURL”,不要在剪贴板上放任何其他内容。然后做:
library(curlconverter)
st <- straighten()
req <- make_req(st)
st 包含一个带有分解请求组件的列表结构,req[[1]]() 是一个可调用的httr 函数。 然而,如果您在运行 make_req() 行后立即移动到新行并使用剪贴板的 paste 功能,您将获得所述功能的格式化源。在这种情况下,那就是:
httr::VERB(
verb = "POST", url = "https://tools.usps.com/tools/app/ziplookup/zipByAddress",
httr::add_headers(
`User-Agent` = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:63.0) Gecko/20100101 Firefox/63.0",
Accept = "application/json, text/javascript, */*; q=0.01",
`Accept-Language` = "en-US,en;q=0.7,fr-BE;q=0.3",
Referer = "https://tools.usps.com/zip-code-lookup.htm?byaddress",
`X-Requested-With` = "XMLHttpRequest",
DNT = "1", Connection = "keep-alive"
),
httr::set_cookies(
nsc_usps_com = "MTc0LjYyLjE2Ny45Nw==",
`NSC_uppmt-xbt8-mc` = "ffffffff3b22378c45525d5f4f58455e445a4a4212d3"
),
body = list(
companyName = "",
address1 = "1+Main+Street",
address2 = "", city = "Cambridge",
state = "MA", zip = ""
),
encode = "form"
)
我们可以从这个自动构建的函数中看出,有 cookie 需要维护,JSON 需要接受,并且——也许——一些其他 HTTP 标头变量需要传递,以及 POST 正文数据。
下一步是对绝对需要的内容进行分类。我没有提示我是如何得出以下内容的,因为您应该做一些工作。为了维护 cookie 状态,我们对源页面进行初始 GET 调用以获取 cookie,只要 R 会话处于活动状态,这些 cookie 就会保持不变。然后,我们传入参数,返回转换后的 JSON:
lookup_zip <- function(address_1, address_2 = "", city = "",
state = "", zip = "", company_name = "") {
suppressPackageStartupMessages({
require("httr", quietly = TRUE, warn.conflicts = FALSE)
require("jsonlite", quietly = TRUE, warn.conflicts = FALSE)
})
# prime cookies
httr::GET(
url = "https://tools.usps.com/zip-code-lookup.htm",
httr::user_agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:63.0) Gecko/20100101 Firefox/63.0")
) -> res
httr::stop_for_status(res)
httr::POST(
url = "https://tools.usps.com/tools/app/ziplookup/zipByAddress",
httr::accept_json(),
httr::user_agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:63.0) Gecko/20100101 Firefox/63.0"),
httr::add_headers(
Referer = "https://tools.usps.com/zip-code-lookup.htm?byaddress",
`X-Requested-With` = "XMLHttpRequest"
),
body = list(
companyName = company_name,
address1 = address_1,
address2 = address_2,
city = city,
state = state,
zip = zip
),
encode = "form"
) -> res
httr::stop_for_status(res)
out <- httr::content(res, as = "text", encoding = "UTF-8")
out <- jsonlite::fromJSON(out)
out
}
所以,当我们运行时:
lookup_zip("1 Main Street", city = "Cambridge", state = "MA")
## $resultStatus
## [1] "SUCCESS"
##
## $addressList
## addressLine1 city state zip5 zip4 carrierRoute countyName deliveryPoint checkDigit cmar elot
## 1 1 MAIN ST CAMBRIDGE MA 02142 1531 C033 MIDDLESEX 99 3 N 0033
## 2 1 MAIN ST CAMBRIDGE MA 02142 1531 C033 MIDDLESEX 99 3 N <NA>
## 3 1 MAIN ST CAMBRIDGE MA 02142 1500 C033 MIDDLESEX 01 4 N <NA>
## 4 1 MAIN ST STE 14 CAMBRIDGE MA 02142 1503 C033 MIDDLESEX 01 1 N <NA>
## 5 1 MAIN ST STE 10 CAMBRIDGE MA 02142 1504 C033 MIDDLESEX 01 0 N <NA>
## 6 1 MAIN ST STE 24 CAMBRIDGE MA 02142 1506 C033 MIDDLESEX 01 8 N <NA>
## 7 1 MAIN ST STE 6 CAMBRIDGE MA 02142 1517 C033 MIDDLESEX 99 9 N <NA>
## 8 1 MAIN ST STE 1 CAMBRIDGE MA 02142 1517 C033 MIDDLESEX 99 9 N <NA>
## 9 1 MAIN ST STE 11 CAMBRIDGE MA 02142 1517 C033 MIDDLESEX 99 9 N <NA>
## 10 1 MAIN ST STE 13 CAMBRIDGE MA 02142 1517 C033 MIDDLESEX 99 9 N <NA>
## 11 1 MAIN ST STE 15 CAMBRIDGE MA 02142 1517 C033 MIDDLESEX 99 9 N <NA>
## 12 1 MAIN ST STE 8 CAMBRIDGE MA 02142 1524 C033 MIDDLESEX 01 8 N <NA>
## 13 1 MAIN ST STE (Range 2 - 5) CAMBRIDGE MA 02142 1599 C033 MIDDLESEX <NA> <NA> N <NA>
## 14 1 MAIN ST STE (Range 7 - 10) CAMBRIDGE MA 02142 1599 C033 MIDDLESEX <NA> <NA> N <NA>
## 15 1 MAIN ST STE (Range 16 - 24) CAMBRIDGE MA 02142 1599 C033 MIDDLESEX <NA> <NA> N <NA>
## 16 1 MAIN ST STE 12 CAMBRIDGE MA 02142 1599 C033 MIDDLESEX 99 9 N <NA>
## 17 1 MAIN ST STE 14 CAMBRIDGE MA 02142 1599 C033 MIDDLESEX 99 9 N <NA>
## elotIndicator recordType dpvConfirmation defaultFlag companyName
## 1 A H D Y <NA>
## 2 <NA> <NA> <NA> <NA> <NA>
## 3 <NA> <NA> <NA> <NA> <NA>
## 4 <NA> <NA> <NA> <NA> BENCHMARKING PARTNERS
## 5 <NA> <NA> <NA> <NA> C MARKET INC
## 6 <NA> <NA> <NA> <NA> SIMAT HELLIESEN & EICHNER
## 7 <NA> <NA> <NA> <NA> <NA>
## 8 <NA> <NA> <NA> <NA> <NA>
## 9 <NA> <NA> <NA> <NA> <NA>
## 10 <NA> <NA> <NA> <NA> <NA>
## 11 <NA> <NA> <NA> <NA> <NA>
## 12 <NA> <NA> <NA> <NA> NEW ENGLAND PENSION
## 13 <NA> <NA> <NA> <NA> <NA>
## 14 <NA> <NA> <NA> <NA> <NA>
## 15 <NA> <NA> <NA> <NA> <NA>
## 16 <NA> <NA> <NA> <NA> CEME
## 17 <NA> <NA> <NA> <NA> <NA>
你不应该对以上内容做的事情:
- 别傻了 #1 :如果您要反复拨打电话,请延迟(即
Sys.sleep(5)。您将免费获得此信息,我的税金支持该网站。您是没什么特别的。
- 别傻了#2:缓存结果,甚至可能在磁盘上。重写函数以使用
memoise 包。
- 别傻了#3:不要出售你正在创建的这个数据库。我会知道你是否这样做(见 #4)
- 不要成为一个混蛋 #4:尽管 SO 固有地声称其他 w/r/t 答案,但上述代码是 AGPL 许可的,因此您有义务发布您基于它编写的任何商业内容的源代码 (如果这是你的最终意图)。我有每天在互联网上爬行的互联网档案规模系统。我会知道的。
这很可能是一种无辜的学术需求,但 SO 充满了(每天)不道德的内容窃贼提出的抓取问题。