爬取Baltic Shipping船舶数据导出CSV,解决分页及空返回问题
船舶数据爬取问题解决方案
核心原因说明
你写的代码抓不到数据是因为目标网站的船舶列表是动态渲染的,初始HTML响应里没有search_results对应的内容,数据是页面加载完成后JS通过AJAX接口请求加载的,直接用requests请求静态页面自然拿不到列表数据。
分页时URL不变也是同样的原因:点击下一页只是触发JS请求下一页的接口数据,局部刷新页面,不会跳转新URL。
最优解决思路
直接调用网站公开的船舶搜索接口,不需要解析HTML,效率远高于用Selenium等模拟浏览器的方案:
- 接口地址:
https://www.balticshipping.com/vessels/search - 请求方式:POST
- 分页通过参数里的
page字段控制,返回格式为JSON,直接可以提取船舶IMO号、名称、详情页链接等所有字段
可运行代码示例
import requests import csv import time # 配置参数 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest' } search_url = 'https://www.balticshipping.com/vessels/search' base_detail_url = 'https://www.balticshipping.com/vessel/imo/' # 要保存的CSV字段,可根据需求自行增减 csv_headers = ['imo', 'vessel_name', 'flag', 'built_year', 'deadweight', 'detail_url'] def get_page_data(page_num): # 构造请求参数,可根据需要修改筛选条件 data = { 'page': page_num, 'per_page': 100, # 单页最多支持100条,减少请求次数 'sort': 'imo:desc', 'search': '', 'filters[flag]': '', 'filters[vessel_type]': '', 'filters[built_year_min]': '', 'filters[built_year_max]': '', 'filters[deadweight_min]': '', 'filters[deadweight_max]': '', } response = requests.post(search_url, headers=headers, data=data) if response.status_code == 200: return response.json() else: print(f"第{page_num}页请求失败,状态码{response.status_code}") return None if __name__ == '__main__': # 先拿第一页数据获取总页数 first_page = get_page_data(1) total_pages = first_page['last_page'] all_data = [] # 循环爬取所有页 for page in range(1, total_pages + 1): print(f"正在爬取第{page}/{total_pages}页") page_data = get_page_data(page) if not page_data: continue # 提取需要的字段 for vessel in page_data['data']: item = { 'imo': vessel['imo'], 'vessel_name': vessel['name'], 'flag': vessel['flag'], 'built_year': vessel['year_built'], 'deadweight': vessel['deadweight'], 'detail_url': base_detail_url + str(vessel['imo']) } all_data.append(item) # 请求间隔,避免IP被封 time.sleep(1) # 保存为CSV with open('baltic_shipping_vessels.csv', 'w', encoding='utf-8-sig', newline='') as f: writer = csv.DictWriter(f, fieldnames=csv_headers) writer.writeheader() writer.writerows(all_data) print(f"爬取完成,共保存{len(all_data)}条数据")
额外说明
- 如果需要详情页的更多维度数据,直接循环上文中得到的
detail_url提取即可,逻辑和列表页请求逻辑一致 - 如果后续接口参数有调整,可以打开浏览器开发者工具的「网络」标签,点击下一页时查看
search接口的实际请求参数自行调整即可
内容的提问来源于stack exchange,提问作者Anwar
相关产品推荐
相关产品推荐

