如何提升嵌套for循环实现的网页爬虫执行速度?
公交数据爬虫性能优化请求
这段R代码用于爬取某交通公司网页,可获取各起讫城市间的公交线路及运营公司信息并整理为表格。代码功能正常,但需处理约650个城市的组合查询,运行3小时仅完成不足5%的任务,恳请提供性能优化方案。
library(RCurl) library(jsonlite) library(rjson) library(dplyr) # 加载城市列表 cidades <- jsonlite::fromJSON("Listas Cidades Artesp.json") empresasXlinhas <- data.frame() # RCURL参数配置 headers = c( "Accept" = "application/json, text/javascript, */*; q=0.01", "Accept-Language" = "en-US,en;q=0.9", "Connection" = "keep-alive", "Content-Type" = "application/x-www-form-urlencoded; charset=UTF-8", "Cookie" = "__RequestVerificationToken_L1RyYW5zcG9ydGVDb2xldGl2bw2=tY-yKlWmbZvAJzMHmITkohPiIos5XkjDBwf1ZBfP_bYWdXJMBF2Qw3z_B-LRVo0kXjdnHqDqsbZ04Zij_PM-wAf4DWVKfnQskOhqo4ANSRc1", "Origin" = "http://extranet.artesp.sp.gov.br", "Referer" = "http://extranet.artesp.sp.gov.br/TransporteColetivo/OrigemDestino?fbclid=IwAR3_hZwajHk_iyU085S1LDTqLCOYLHIZ5K825XgPGcB4tMI0EuCJpQNrJHM", "User-Agent" = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36", "X-Requested-With" = "XMLHttpRequest" ) # 网页爬取逻辑 for (x in cidades$Codigo){ for (y in cidades$Codigo){ if (x != y){ params = paste("origem=",x,"&destino=",y,"&__RequestVerificationToken=Z-wXmGOb9pnQbmkfcQXmChT-6uc3YfGjftHwK4HnC9SDCaKmzIafo7AI3lChBY6YDBHdpT_X98mSHGAr_YrTNgKiepKxKraGu7p6PI7dV4g1", sep ="") res <- postForm("http://extranet.artesp.sp.gov.br/TransporteColetivo/OrigemDestino/GetGrid", .opts=list(postfields = params, httpheader = headers, followlocation = TRUE), style = "httppost") if (res != "[]"){ print(paste(x,y)) empresa <- jsonlite::fromJSON(res)[[2]] empresa <- empresa %>% mutate(cod_origem = x, cod_destino = y) empresasXlinhas <- rbind(empresasXlinhas, empresa) } } } }
核心优化方案
1. 并行化请求(最关键提速点)
- 使用
future+furrr或parallel包,将所有有效城市组合的请求任务拆分到多个CPU核心并行执行,彻底消除单线程串行等待HTTP响应的时间浪费。 - 实现思路:先生成所有
x≠y的城市组合,再用future_map批量处理每个组合的请求与数据解析。
2. 替换循环中的rbind操作
- 循环内反复
rbind会频繁复制整个数据框,数据量越大效率越低。改为用列表存储每个请求返回的empresa数据,最后通过dplyr::bind_rows()一次性合并,能大幅提升数据拼接效率。
3. 优化HTTP请求工具与配置
- 替换
RCurl为更高效的httr2或httr包,这类现代HTTP工具性能更优,API设计更简洁。 - 启用HTTP连接复用,设置合理的超时参数,避免每次请求都重新建立TCP连接。
- 验证硬编码的
__RequestVerificationToken是否长期有效,若存在失效风险,需添加动态获取逻辑。
4. 减少重复请求量
- 若城市间线路数据是双向对称的(即x到y与y到x的线路信息一致),可只请求一半的城市组合,后续直接复制反向数据,减少50%的请求量。
5. 预处理城市组合
- 提前生成所有有效
(x,y)对并过滤掉x=y的无效组合,避免循环内反复判断,示例代码:city_pairs <- expand.grid(x = cidades$Codigo, y = cidades$Codigo) %>% filter(x != y)
6. 添加错误重试机制
- 网络请求偶尔会失败,用
purrr::insistently添加自动重试逻辑,避免个别请求失败中断整个流程,降低人工干预成本。
7. 分批处理并保存中间结果
- 每处理完一批请求就将结果写入本地文件(如
readr::write_csv),既避免程序崩溃导致数据丢失,也能减少内存占用。
内容的提问来源于stack exchange,提问作者L3A
相关产品推荐
相关产品推荐

