Scrapy爬取含#!的AJAX URL遇301重定向问题求解
解决Scrapy爬取带#!的AJAX URL时的301重定向问题
你遇到的问题确实和URL里的#!(hashbang)有关——这种模式是早期AJAX网站用来支持搜索引擎爬取的方案,服务器会识别_escaped_fragment_参数来返回渲染后的页面,但直接请求带#!的URL时,Scrapy不会自动处理这个转换,导致服务器返回301重定向到首页。下面是具体的解决步骤和修改后的代码:
核心思路
要让服务器返回正确的内容,需要把带#!的URL转换为搜索引擎友好的格式:将#!替换为?_escaped_fragment_=,同时保留原#!后面的所有路径内容(注意不需要额外编码,原URL里的编码已经符合要求)。
修改后的蜘蛛代码
import json import scrapy import re import pkgutil import urllib.parse from scrapy.loader import ItemLoader from annonces_spiders.items import AnnonceItem class GlenMarchSpider(scrapy.Spider): name = 'annonces_results' def __init__(self, *args, **kwargs): data_file = pkgutil.get_data("annonces_spiders", "json/input/db_scrap_url_lp_js_10000_reduced.json") self.data = json.loads(data_file) def start_requests(self): # 模拟浏览器的User-Agent,避免被服务器识别为爬虫 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } for item in self.data: original_url = item['url_lp'] # 处理hashbang格式的URL if '#!' in original_url: parsed_url = urllib.parse.urlsplit(original_url) # 提取#!后的片段(去掉开头的!) fragment_content = parsed_url.fragment[2:] if parsed_url.fragment.startswith('!') else parsed_url.fragment # 构造新的URL,将片段作为_escaped_fragment_参数 new_url = urllib.parse.urlunsplit( (parsed_url.scheme, parsed_url.netloc, parsed_url.path, f'_escaped_fragment_={fragment_content}', '') ) else: new_url = original_url request = scrapy.Request(new_url, callback=self.parse, headers=headers) request.meta['item'] = item yield request def parse(self, response): item = response.meta['item'] item['results'] = [] for caritem in response.css("li.li-result"): data = AnnonceItem() data["marque"] = caritem.css("span.brand::text").extract_first().capitalize().replace(" ", "").strip() data["model"] = caritem.css("span.sub-title::text").extract_first().capitalize().replace(" ", "").strip() data["model_year"] = caritem.css("li:nth-child(3) > div.upper::text").extract_first().replace(" ", "").strip() data["price_str"] = caritem.css("p.prix::text").extract_first().strip() if "NC" not in data["price_str"]: data["price_int"] = int(caritem.css("p.prix::text").extract_first().replace("€", "").replace(" ", "").strip()) else: data["price_int"] = None data["annonce_date"] = caritem.css("p.btn-publication::text").extract_first().strip().replace("/", "-") data["country"] = caritem.css("div.location > img::attr(alt)").extract_first().capitalize().strip() item['results'].append(data) yield item
关键修改点说明
- URL转换逻辑:用
urllib.parse模块拆分原始URL,提取#!后的内容,将其作为_escaped_fragment_参数拼接到URL中,确保服务器能识别并返回渲染后的页面。 - 添加User-Agent:模拟浏览器请求头,避免服务器因识别为爬虫而返回异常内容或重定向。
额外检查建议
- 运行爬虫后查看日志,如果仍有重定向,可以尝试添加
dont_redirect=True到scrapy.Request参数中,但优先确保URL转换正确。 - 如果服务器返回的内容还是不符合预期,可以检查响应的
Status Code和内容,确认是否需要处理Cookies或其他请求头。
内容的提问来源于stack exchange,提问作者lf_celine
相关产品推荐
相关产品推荐

