Scrapy 遇到的小坑_关于payload参数_scrapy第一次发送POST请求

本文通过实战案例解析了Scrapy框架中POST请求的注意事项,特别是如何处理Content-Length字段导致的问题,对比requests与Scrapy的不同之处。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Scrapy框架第一发送POST请求遇到的小坑

前言: 爬取一个数据开发平台 悦采 网, 爬取上面的招标_采购信息。


小坑:requests能获取到内容,改成scrapy却不能获取到内容,而且请求信息之类的条件都一摸一样?

解决方式:

问题就出在headers上面:去掉 headers里面的 Content-Length 这一栏
具体原因如下:
https://stackoverflow.com/questions/42248903/scrapy-post-request-not-working-400-bad-request

首先思路,分析网站,找规律,我感觉这个是重要的一步。

1.先看看网页结构,找规律。
这里写图片描述
我们发现只要找到这个url然后请求,进入详细页面,就找到想要的数据了。
这里写图片描述
这里写图片描述
这里写图片描述

开始找规律爬取数据

这里写图片描述

我们找到了别人的api接口,里面有公司的一些相关信息,可以拼接id访问每个公司url
这里写图片描述

但是这里的url是一个post请求,而且需要Payload,我一开始没注意, 就当成普通的POST请求去使用,一直没有成功报400
这里写图片描述
这是我爬取拉钩招聘信息的时候模拟POST请求发送的数据,也成功了, 我琢磨了好久为什么,才发现POST请求 需要的是Payload 有效载荷
我百度发现要把数据转换为json数据发送

import requests
import json


class YuecaiSpider(object):
    def __init__(self):
        self.headers = {
            'Content-Type': 'application/json',
            'Host': 'iris.yuecai.com',
            'Origin': 'http://www.yuecai.com',
            # 'Referer': 'http://www.yuecai.com/purchase/?SiteID=21',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
        }
        self.data = {
            "page": 0,
            "size": 20,
            "sort": None,
            "teseData": 2,
            "word": None,
            "zone": None,
        }

    def start_requests(self):
        url = "http://iris.yuecai.com/iris/v1/purchase/search"
        res = requests.post(url, headers=self.headers, data=json.dumps(self.data))  # 这里要转换为json数据
        print(res.status_code)
        print(res.text)


if __name__ == '__main__':
    yuecai = YuecaiSpider()
    yuecai.start_requests()
  • 用requests写测试脚本的时候,一点问题没有,但是我改成scrapy后,一直没有数据。我不知道是为什么??
import scrapy
import json


class YuecaiSpider(scrapy.Spider):
    name = 'yuecai'
    allowed_domains = ['yuecai.com']
    start_urls = ['http://iris.yuecai.com/iris/v1/purchase/search']

    site_name = '悦采网数据平台'
    version = '1.0'

    def __init__(self):
        super(YuecaiSpider, self).__init__()
        self.headers = {
            # 'Accept': 'application/json, text/javascript, */*; q=0.01',
            # 'Accept-Encoding': 'gzip, deflate',
            # 'Accept-Language': 'zh-CN,zh;q=0.9',
            # 'Connection': 'keep - alive',
            # 'Content - Length': '69',
            'Content-Type': 'application/json',
            'Host': 'iris.yuecai.com',
            'Origin': 'http://www.yuecai.com',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
        }

        self.data = {
            'word': None,   # 'NULL'
            'zone': None,    # 注意这边特别坑的  有的就是需要'null'这种数据
            'page': '1',     # 参数该用字符用字符
            'size': '20',    # 
            'sort': None,
            'teseData': '2',
        }

    def start_requests(self):
        url = "http://iris.yuecai.com/iris/v1/purchase/search"
        yield scrapy.Request(
            url,
            method="POST",
            headers=self.headers,
            body=json.dumps(self.data),   # 这边数据也是要转换成json数据
            dont_filter=True,
            callback=self.parse,
        )

    def parse(self, response):
        print("*" * 50)
        print(response.status)
        print(response.text)
        print("*" * 50)

Scrapy 关于headers参数注意

# 有时候明明 requests 或者 postman 请求都是正常的, 但是改成scrapy就不行了,
# 原因往往出在headers里面,我不确定是不是scrapy做了过滤之类的操作,但是把不必要的参数注释就好了
# 写爬虫的话一定要对http协议有了解,知道headers里面那些参数什么意思,
# 比如referer (其实历史拼错的单词) 意思是从那个链接跳转来的,常用于图片等媒体资源防盗链,推荐一本名叫《图解http》的书
headers = {
             'Accept': 'application/json, text/javascript, */*; q=0.01',
            # 'Accept-Encoding': 'gzip, deflate',     #  注释
            # 'Accept-Language': 'zh-CN,zh;q=0.9',  # 注释
            # 'Connection': 'keep - alive',     # 注释
            # 'Content - Length': '69',   #  务必要注释掉 
            'Content-Type': 'application/json',   
            'Host': 'iris.yuecai.com',
            'Origin': 'http://www.yuecai.com',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
        }


把上面的请求的参数加了引号, 需要’null’的改成None(但是有的网站POST请求参数就是’null’)
好吧看看我运行的结果把。

这里写图片描述

2018/11/29 更新

评论那位小哥! 我在我电脑上测试 没有问题, 由于评论下面贴代码,格式很乱,我就贴在文章里面了,效果图如下。
在这里插入图片描述
测试代码如下:

# -*- coding:utf-8 -*-
# @Author: wg
# @Time: 2018/11/29 15:02
# @Desc: 
"""

"""
import scrapy


class TestCnSpider(scrapy.Spider):
    name = 'test_cn'
    allowed_domains = ['org.cn']
    start_urls = ['http://gs.amac.org.cn/amac-infodisc/api/pof/fund?rand=0.8266535799537897&page=0&size=20']
    """
    POST http://gs.amac.org.cn/amac-infodisc/api/pof/fund?rand=0.4768735209349304&page=0&size=20 HTTP/1.1
    Host: gs.amac.org.cn
    Proxy-Connection: keep-alive
    Content-Length: 2
    Accept: application/json, text/javascript, */*; q=0.01
    Origin: http://gs.amac.org.cn
    X-Requested-With: XMLHttpRequest
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36
    Content-Type: application/json
    Referer: http://gs.amac.org.cn/amac-infodisc/res/pof/fund/index.html
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    """
    headers = {
        "Host": "gs.amac.org.cn",
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "Origin": "http://gs.amac.org.cn",
        "X-Requested-With": "XMLHttpRequest",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "Content-Type": "application/json",
        "Referer": "http://gs.amac.org.cn/amac-infodisc/res/pof/fund/index.html",
        "Accept-Language": "zh-CN,zh;q=0.9",
    }

    def start_requests(self):
        yield scrapy.Request(
            self.start_urls[0],
            method="POST",
            headers=self.headers,
            body="{}",
            callback=self.parse,
            dont_filter=True
        )

    def parse(self, response):
        print(response.text)
<think>我们正在讨论如何设置Scrapy中的POST请求参数。根据引用,我们可以使用scrapy.FormRequest或scrapy.Request来发送POST请求,并通过formdata参数传递POST数据。 关键点: 1. 使用scrapy.FormRequest发送POST请求时,通过formdata参数传递字典形式的参数。 2. 也可以使用scrapy.Request,但需要设置method='POST',并通过body参数传递编码后的数据(通常使用urlencode),同时设置合适的Content-Type头(如'application/x-www-form-urlencoded')。 根据引用[1]和引用[3]: - scrapy.FormRequest是专门用于处理表单POST请求的,它默认设置method为POST,并且会自动设置Content-Type为'application/x-www-form-urlencoded',同时将formdata字典编码为表单数据。 根据引用[2]和引用[4]: - 也可以使用scrapy.Request,通过指定method='POST',然后自己处理数据的编码和设置请求头。 因此,有两种方法: 方法1:使用scrapy.FormRequest(推荐,因为更简单) yield scrapy.FormRequest( url=url, formdata={...}, # 字典形式的POST数据 callback=self.parse ) 方法2:使用scrapy.Request(更灵活,可以处理非表单数据,如JSON) - 如果发送表单数据(application/x-www-form-urlencoded): yield scrapy.Request( url=url, method='POST', body=urllib.parse.urlencode({...}), # 将字典编码为查询字符串 headers={'Content-Type': 'application/x-www-form-urlencoded'}, callback=self.parse ) - 如果发送JSON数据: import json yield scrapy.Request( url=url, method='POST', body=json.dumps({...}), # 将字典转换为JSON字符串 headers={'Content-Type': 'application/json'}, callback=self.parse ) 注意:引用[4]中展示了使用scrapy.FormRequest发送GET请求(通过method='GET')的例子,但通常我们使用它发送POST请求。在发送POST请求时,我们不需要指定method,因为FormRequest默认就是POST。 下面给出具体示例: 示例1:使用scrapy.FormRequest发送表单POST请求 class MySpider(scrapy.Spider): name = 'post_example' start_urls = ['https://example.com/login'] def start_requests(self): # 假设我们要登录,提交表单 login_data = { 'username': 'user', 'password': 'pass' } yield scrapy.FormRequest( url='https://example.com/login', formdata=login_data, callback=self.after_login ) def after_login(self, response): # 处理登录后的响应 pass 示例2:使用scrapy.Request发送JSON格式的POST请求 class MySpider(scrapy.Spider): name = 'post_example_json' start_urls = ['https://example.com/api'] def start_requests(self): # 构造JSON数据 json_data = { 'key1': 'value1', 'key2': 'value2' } yield scrapy.Request( url='https://example.com/api', method='POST', body=json.dumps(json_data), headers={'Content-Type': 'application/json'}, callback=self.parse ) def parse(self, response): # 处理响应 pass 总结: - 对于表单数据,使用scrapy.FormRequest和formdata参数是最简便的方式。 - 对于JSON或其他格式,使用scrapy.Request,并手动设置body和请求头。 注意:在引用[3]中提到,不推荐使用Scrapy发送POST请求,因为配置复杂。但实际上,ScrapyPOST请求的支持是良好的,只要按照上述方法正确配置即可。 最后,关于引用[4]中提到的使用scrapy.FormRequest发送GET请求(通过method='GET')的方式,虽然可以,但通常GET请求参数是通过URL的查询字符串传递的,所以更常见的做法是使用scrapy.Request的params参数(对于GET)或者直接构造带参数的URL。 因此,针对POST请求,我们主要使用上述两种方法。 相关问题: 1. Scrapy发送POST请求时,如何处理CSRF令牌? 2. 如何在Scrapy发送multipart/form-data类型的POST请求(例如文件上传)? 3. Scrapy中如何管理登录后的会话(session)? 4. 如何调试Scrapy发送POST请求的数据和头部? 5. ScrapyPOST请求失败时如何重试?</think>### 在Scrapy中设置POST请求参数Scrapy中设置POST请求参数主要有两种推荐方法,根据参数格式和需求选择: #### 方法1:使用`scrapy.FormRequest`(推荐表单提交) ```python import scrapy class MySpider(scrapy.Spider): name = 'post_example' def start_requests(self): post_url = "https://example.com/login" post_data = { 'username': 'your_username', 'password': 'your_password', 'remember_me': '1' } yield scrapy.FormRequest( url=post_url, formdata=post_data, # 关键参数 callback=self.after_login ) def after_login(self, response): # 处理登录后的响应 if "Welcome" in response.text: self.logger.info("Login successful") ``` **特点**: 1. 自动设置`Content-Type`为`application/x-www-form-urlencoded` 2. 自动处理参数编码 3. 支持多值参数(如:`{'choices': ['a', 'b']}`) #### 方法2:使用`scrapy.Request`(推荐JSON/自定义格式) ```python import scrapy import json class ApiSpider(scrapy.Spider): name = 'api_example' def start_requests(self): api_url = "https://api.example.com/v1/data" json_data = { 'query': 'scrapy', 'filters': { 'category': 'books', 'year': 2023 } } yield scrapy.Request( url=api_url, method='POST', body=json.dumps(json_data), # 直接设置请求体 headers={'Content-Type': 'application/json'}, callback=self.parse_api ) def parse_api(self, response): data = json.loads(response.text) # 处理API响应 ``` **特点**: 1. 灵活支持任意格式(JSON/XML等) 2. 需要手动设置`Content-Type`头部 3. 使用`body`参数直接传递编码后的数据 #### 关键注意事项: 1. **参数编码**: - 表单数据:`FormRequest`自动进行URL编码 - JSON数据:需手动使用`json.dumps()` - 文件上传:使用`files`参数(需要自定义中间件) 2. **动态参数**: ```python def parse_page(self, response): token = response.css('input#csrf::attr(value)').get() yield scrapy.FormRequest( url='https://example.com/action', formdata={'csrf_token': token, 'page': str(response.meta['page'])}, callback=self.next_page ) ``` 3. **调试技巧**: ```python # 在settings.py中启用调试 DOWNLOADER_MIDDLEWARES = { 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110, } # 查看实际发送请求 scrapy shell --nolog 'https://example.com' >>> req = scrapy.FormRequest(url, formdata=params) >>> fetch(req) # 查看实际请求 ``` 4. **安全建议**: - 敏感参数通过`scrapy.Request`的`meta`传递 - 使用`custom_settings`管理API密钥: ```python custom_settings = { 'API_KEY': 'your_secret_key', 'DEFAULT_REQUEST_HEADERS': { 'Authorization': 'Bearer %(API_KEY)s' } } ``` [^1][^3][^4]
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值