如何在rvest的html_session中使用POST方法获取完整评论
解决TripAdvisor评论展开的POST请求问题(rvest+httr实现)
先呼应一下你提到的合规问题——确实TripAdvisor的使用条款禁止爬取,咱们就纯从技术角度探讨POST请求的实现哈!
你现在遇到的POST请求返回空body的问题,核心原因是请求参数、请求头或会话配置不完整,TripAdvisor的反爬机制会校验多个细节,加上两个POST请求存在依赖关系,必须按顺序在同一会话中发送。下面一步步给你梳理解决方案:
1. 理清两个POST请求的依赖关系
从你观察的网络流量来看:
- 第一个POST是前置校验请求,用于验证会话合法性,触发评论展开的前置逻辑;
- 第二个POST才是核心数据请求,返回完整的评论内容;
- 两个请求必须共享同一个会话(Cookie),否则服务器会拒绝返回有效内容。
2. 关键配置修正要点
(1)复用会话保持Cookie
必须用html_session初始化会话,所有请求都通过这个会话发送,确保Cookie自动传递——TripAdvisor会严格校验会话的一致性。
(2)完善请求头
TripAdvisor会校验以下关键请求头,必须和抓包结果一致:
Referer:必须是原页面URL;X-Requested-With:固定为XMLHttpRequest(标识AJAX请求);Accept:匹配服务器预期的响应类型;User-Agent:尽量用真实浏览器的UA,避免被识别为爬虫。
(3)正确编码请求体
你之前用encode="raw"是错误的,TripAdvisor的POST请求采用application/x-www-form-urlencoded编码,应该用encode="form",或者将参数整理为列表(httr会自动编码)。
3. 修正后的完整代码示例
library(rvest) library(httr) # 原页面URL base_url <- "https://www.tripadvisor.com/Hotel_Review-g33657-d85704-Reviews-Hotel_Bristol-Steamboat_Springs_Colorado.html" # 初始化会话,获取必要的Cookie和页面上下文 session <- html_session( base_url, user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36") ) # 第一个POST请求(前置校验) first_post_url <- "https://www.tripadvisor.com/OverlayWidgetAjax?Mode=EXPANDED_HOTEL_REVIEWS_RESP&metaReferer=" first_post_body <- list( reviews = "556957481,511497076,556144452,554686822,548218482", contextChoice = "DETAIL_HR", haveJses = "earlyRequireDefine,amdearly,global_error,long_lived_global,apg-Hotel_Review,apg-Hotel_Review-in,bootstrap,desktop-rooms-guests-dust-en_US,responsive-calendar-templates-dust-en_US,taevents", haveCsses = "apg-Hotel_Review-in", Action = "install" ) # 发送第一个请求,复用会话 first_response <- POST( url = first_post_url, config = list(referer = base_url), body = first_post_body, encode = "form", add_headers( "X-Requested-With" = "XMLHttpRequest", "Accept" = "*/*" ), session = session ) # 第二个POST请求(获取完整评论,URL和参数需与抓包完全匹配) second_post_url <- "https://www.tripadvisor.com/OverlayWidgetAjax?Mode=EXPANDED_HOTEL_REVIEWS_RESP&metaReferer=Hotel_Review-g33657-d85704-Reviews-Hotel_Bristol-Steamboat_Springs_Colorado.html" second_post_body <- list( widgetId = "EXPANDED_HOTEL_REVIEWS", # 从抓包中提取的关键参数 reviews = "556957481,511497076,556144452,554686822,548218482", contextChoice = "DETAIL_HR", Action = "refresh" ) # 发送第二个请求,复用会话 second_response <- POST( url = second_post_url, config = list(referer = base_url), body = second_post_body, encode = "form", add_headers( "X-Requested-With" = "XMLHttpRequest", "Accept" = "text/html, */*; q=0.01" ), session = session ) # 解析完整评论内容 full_reviews <- content(second_response, "html") %>% html_elements(".partial_entry") %>% html_text(trim = TRUE) print(full_reviews)
4. 额外排查技巧
如果仍然返回空响应,建议:
- 用
httr::verbose()添加到请求中,打印完整的请求/响应细节,和抓包结果逐一对比; - 检查抓包时的所有参数(包括隐藏参数,比如
widgetId、pageNumber)是否完全复制; - 确认会话中的Cookie是否和浏览器中的一致(可以用
session$cookies查看)。
再次强调:以上内容仅为技术探讨,实际使用请严格遵守TripAdvisor的使用条款!
内容的提问来源于stack exchange,提问作者Yifu Yan
相关产品推荐
相关产品推荐

