python使用scrapy发送post请求的坑

使用requests发送post请求

先来看看使用requests来发送post请求是多少好用,发送请求

Requests 简便的 API 意味着所有 HTTP 请求类型都是显而易见的。例如,你可以这样发送一个 HTTP POST 请求:

>>>r = requests.post('http://httpbin.org/post', data = {'key':'value'})

使用data可以传递字典作为参数,同时也可以传递元祖

>>>payload = (('key1', 'value1'), ('key1', 'value2'))
>>>r = requests.post('http://httpbin.org/post', data=payload)
>>>print(r.text)
{
 ...
 "form": {
  "key1": [
   "value1",
   "value2"
  ]
 },
 ...
}

传递json是这样

>>>import json

>>>url = 'https://api.github.com/some/endpoint'
>>>payload = {'some': 'data'}

>>>r = requests.post(url, data=json.dumps(payload))

2.4.2 版的新加功能:

>>>url = 'https://api.github.com/some/endpoint'
>>>payload = {'some': 'data'}

>>>r = requests.post(url, json=payload)

也就是说,你不需要对参数做什么变化,只需要关注使用data=还是json=,其余的requests都已经帮你做好了。

使用scrapy发送post请求

通过源码可知scrapy默认发送的get请求,当我们需要发送携带参数的请求或登录时,是需要post、请求的,以下面为例

from scrapy.spider import CrawlSpider
from scrapy.selector import Selector
import scrapy
import json
class LaGou(CrawlSpider):
  name = 'myspider'
  def start_requests(self):
    yield scrapy.FormRequest(
      url='https://www.******.com/jobs/positionAjax.json?city=%E5%B9%BF%E5%B7%9E&needAddtionalResult=false',
      formdata={
        'first': 'true',#这里不能给bool类型的True,requests模块中可以
        'pn': '1',#这里不能给int类型的1,requests模块中可以
        'kd': 'python'
      },这里的formdata相当于requ模块中的data,key和value只能是键值对形式
      callback=self.parse
    )
  def parse(self, response):
    datas=json.loads(response.body.decode())['content']['positionResult']['result']
    for data in datas:
      print(data['companyFullName'] + str(data['positionId']))

官方推荐的 Using FormRequest to send data via HTTP POST

return [FormRequest(url="http://www.example.com/post/action",
          formdata={'name': 'John Doe', 'age': '27'},
          callback=self.after_post)]

这里使用的是FormRequest,并使用formdata传递参数,看到这里也是一个字典。

但是,超级坑的一点来了,今天折腾了一下午,使用这种方法发送请求,怎么发都会出问题,返回的数据一直都不是我想要的

return scrapy.FormRequest(url, formdata=(payload))

在网上找了很久,最终找到一种方法,使用scrapy.Request发送请求,就可以正常的获取数据。

代码如下:

return scrapy.Request(url, body=json.dumps(payload), method='POST', headers={'Content-Type': 'application/json'},)

参考:Send Post Request in Scrapy

my_data = {'field1': 'value1', 'field2': 'value2'}
request = scrapy.Request( url, method='POST',
             body=json.dumps(my_data),
             headers={'Content-Type':'application/json'} )

FormRequest 与 Request 区别

在文档中,几乎看不到差别,

The FormRequest class adds a new argument to the constructor. The remaining arguments are the same as for the Request class and are not documented here.
Parameters: formdata (dict or iterable of tuples) – is a dictionary (or iterable of (key, value) tuples) containing HTML Form data which will be url-encoded and assigned to the body of the request.

说FormRequest新增加了一个参数formdata,接受包含表单数据的字典或者可迭代的元组,并将其转化为请求的body。并且FormRequest是继承Request的

class FormRequest(Request):

  def __init__(self, *args, **kwargs):
    formdata = kwargs.pop('formdata', None)
    if formdata and kwargs.get('method') is None:
      kwargs['method'] = 'POST'

    super(FormRequest, self).__init__(*args, **kwargs)

    if formdata:
      items = formdata.items() if isinstance(formdata, dict) else formdata
      querystr = _urlencode(items, self.encoding)
      if self.method == 'POST':
        self.headers.setdefault(b'Content-Type', b'application/x-www-form-urlencoded')
        self._set_body(querystr)
      else:
        self._set_url(self.url + ('&' if '?' in self.url else '?') + querystr)
      ###

def _urlencode(seq, enc):
  values = [(to_bytes(k, enc), to_bytes(v, enc))
       for k, vs in seq
       for v in (vs if is_listlike(vs) else [vs])]
  return urlencode(values, doseq=1)

最终我们传递的{‘key': ‘value', ‘k': ‘v'}会被转化为'key=value&k=v' 并且默认的method是POST,再来看看Request

class Request(object_ref):

  def __init__(self, url, callback=None, method='GET', headers=None, body=None,
         cookies=None, meta=None, encoding='utf-8', priority=0,
         dont_filter=False, errback=None, flags=None):

    self._encoding = encoding # this one has to be set first
    self.method = str(method).upper()

默认的方法是GET,其实并不影响。仍然可以发送post请求。这让我想起来requests中的request用法,这是定义请求的基础方法。

def request(method, url, **kwargs):
  """Constructs and sends a :class:`Request <Request>`.

  :param method: method for the new :class:`Request` object.
  :param url: URL for the new :class:`Request` object.
  :param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
  :param data: (optional) Dictionary or list of tuples ``[(key, value)]`` (will be form-encoded), bytes, or file-like object to send in the body of the :class:`Request`.
  :param json: (optional) json data to send in the body of the :class:`Request`.
  :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
  :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
  :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload.
    ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')``
    or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string
    defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers
    to add for the file.
  :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
  :param timeout: (optional) How many seconds to wait for the server to send data
    before giving up, as a float, or a :ref:`(connect timeout, read
    timeout) <timeouts>` tuple.
  :type timeout: float or tuple
  :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``.
  :type allow_redirects: bool
  :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
  :param verify: (optional) Either a boolean, in which case it controls whether we verify
      the server's TLS certificate, or a string, in which case it must be a path
      to a CA bundle to use. Defaults to ``True``.
  :param stream: (optional) if ``False``, the response content will be immediately downloaded.
  :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
  :return: :class:`Response <Response>` object
  :rtype: requests.Response

  Usage::

   >>> import requests
   >>> req = requests.request('GET', 'http://httpbin.org/get')
   <Response [200]>
  """

  # By using the 'with' statement we are sure the session is closed, thus we
  # avoid leaving sockets open which can trigger a ResourceWarning in some
  # cases, and look like a memory leak in others.
  with sessions.Session() as session:
    return session.request(method=method, url=url, **kwargs)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Pycharm+Scrapy安装并且初始化项目的方法

    前言 Scrapy是一个开源的网络爬虫框架,Python编写的.最初设计用于网页抓取,也可以用来提取数据使用API或作为一个通用的网络爬虫.是数据采集不可必备的利器. 安装 pip install scrapy 如果使用上面的命令太慢.国内可以使用豆瓣源进行加速. pip install -i https://pypi.douban.com/simple scrapy 注意要写错了,是 https://pypi.douban.com/simple 很多包都可以使用这个源进行加速,这也是pip的一

  • pycharm下打开、执行并调试scrapy爬虫程序的方法

    首先得有一个Scrapy项目,我在Desktop上新建一个Scrapy的项目叫test,在Desktop目录打开命令行,键入命令:scrapy startproject test1 目录结构如下: 打开Pycharm,选择open 选择项目,ok 打开如下界面之后,按alt + 1, 打开project 面板 在test1/spiders/,文件夹下,新建一个爬虫spider.py, 注意代码中的name="dmoz".这个名字后面会用到. 在test1目录和scrapy.cfg同级目

  • pycharm创建scrapy项目教程及遇到的坑解析

    前言 最近学习scrapy爬虫框架,在使用pycharm安装scrapy类库及创建scrapy项目时花费了好长的时间,遇到各种坑,根据网上的各种教程,花费了一晚上的时间,终于成功,其中也踩了一些坑,现在整理下相关教程,希望帮助那些遇到和我一样问题的码农. 1.环境 操作系统:windows10. python版本:python3.7,必须使用Anaconda,目前是Anaconda5.3.1.下载地址:https://www.anaconda.com/download/ 下载64位的安装包.sc

  • pycharm 批量修改变量名称的方法

    当代码已经写得差不多,发现某个变量名需要修改,但代码中很多地方都有该变量,一一修改太麻烦了,在不同的情景下,可以采取更加简便的方法,如下介绍: 方法一:rename方法 S1 把光标移动到要修改的变量名称上 S2 右键-refactor - rename- 确定 S3 在弹出来的框中,选择 rename code occurences,即修改所有重复出现的变量名 S4 变量周围出现红色框,修改变量,确定 S5 其他位置的该变量会被同时修改 方法二:查找替换方法 前提:变量名只用于变量,没有其他用

  • 在Pycharm中执行scrapy命令的方法

    当你检查scrapy二进制文件时,你会注意到这么一段python script #!/usr/bin/python from scrapy.cmdline import execute execute() 这意味着 一个scrapy命令,比如 scrapy crawl IcecatCrawler 也可以这么表达: python /Library/Python/2.7/site-packages/scrapy/cmdline.py crawl IcecatCrawler 所以,只能我们找到pych

  • Pycharm简单使用教程(入门小结)

    1.下载pycharm pycharm是一种Python IDE,能够帮助我们在编写代码时提高效率. 网上提供的有专业版和教育版之分. 专业版是收费的,功能更全面点. 教育版或社区版是阉割版本,但它是免费的. 2.pycharm的安装 比较简单,官网下载 备注: 刚下载好的pycharm无法运行程序" Cannot start process, the working directory-", 两种解决方法 1.选择Run-Edit configurations.然后点击Environ

  • python使用scrapy发送post请求的坑

    使用requests发送post请求 先来看看使用requests来发送post请求是多少好用,发送请求 Requests 简便的 API 意味着所有 HTTP 请求类型都是显而易见的.例如,你可以这样发送一个 HTTP POST 请求: >>>r = requests.post('http://httpbin.org/post', data = {'key':'value'}) 使用data可以传递字典作为参数,同时也可以传递元祖 >>>payload = (('ke

  • Python使用requests发送POST请求实例代码

    本文研究的主要是Python使用requests发送POST请求的相关内容,具体介绍如下. 一个http请求包括三个部分,为别为请求行,请求报头,消息主体,类似以下这样: 请求行 请求报头 消息主体 HTTP协议规定post提交的数据必须放在消息主体中,但是协议并没有规定必须使用什么编码方式.服务端通过是根据请求头中的Content-Type字段来获知请求中的消息主体是用何种方式进行编码,再对消息主体进行解析.具体的编码方式包括: application/x-www-form-urlencode

  • 如何基于Python + requests实现发送HTTP请求

    这篇文章主要介绍了如何基于Python + requests实现发送HTTP请求,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.在接口自动化测试过程中,存在两种情况: 一种是不需要鉴权的接口,可以直接访问的. 还有一种情况是需要鉴权才可以访问的接口. 这里我们通过Python + requests 实现这两种发送请求的方法 """ ============================ author:Treasure丶

  • 关于Python中request发送post请求传递json参数的问题

    昨天遇到了一个奇怪的问题,在Python中需要传递dict参数,利用json.dumps将dict转为json格式用post方法发起请求: params = {"score":{"gt":"80", "lt":"90"}} request.post(url, json.dumps(params)) 但是在服务端接收到的参数日志为: Parameters: {"sno"=>"

  • 基于Python模拟浏览器发送http请求

    1.使用 urllib2 实现 #! /usr/bin/env python # -*- coding=utf-8 -*- import urllib2 url="https://www.baidu.com" req_header = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/53

  • Python批量发送post请求的实现代码

    昨天学了一天的Python(我的生产语言是java,也可以写一些shell脚本,算有一点点基础),今天有一个应用场景,就正好练手了. 这个功能之前再java里写过,比较粗糙,原来是在我本机跑的,今天老大要求要随时保持请求,就用Python改写了下,省的又把一个有跟多杂项的jar包传到服务器,省空间又不乱,而且好读. 先附上java代码: package xxxxxx.base; import java.util.Random; import org.apache.commons.lang3.St

  • 利用python的socket发送http(s)请求方法示例

    前言 这是个在写计算机网络课设的时候碰到的问题,卡了我一天,所以总结一下. 其实在之前就有用requests写过python爬虫,但是计算机网络要求更底层的实现,刚好我看到了[这篇文章]1结果发现他就是用socket来实现的请求,所以就学习了. 本来也觉得应该不难,毕竟就是建立tcp连接. 原网站的例子如下: def fetch(url): sock = socket.socket() # 建立socket sock.connect(('xkcd.com', 80)) # 远程连接 reques

  • python实现测试工具(一)——命令行发送get请求

    本系列教程我们将使用python实现一些简单的测试工具,为了尽可能的简单,我们的工具以命令行工具为主. 本系列教程使用的python版本是3.6.3. 背景 这一节我们实现简单的命令行发送get请求的工具,使用方式如下: python get.py www.v2ex.com/api/nodes/show.json\?name\=python 接口地址: http://www.v2ex.com/api/nodes/show.json?name=python 状态码: 200 Headers: Da

  • spring boot RestTemplate 发送get请求的踩坑及解决

    spring boot RestTemplate 发送get请求踩坑 闲话少说,代码说话 RestTemplate 实例 手动实例化,这个我基本不用 RestTemplate restTemplate = new RestTemplate(); 依赖注入,通常情况下我使用 java.net 包下的类构建的 SimpleClientHttpRequestFactory @Configuration public class RestConfiguration { @Bean @Conditiona

  • 关于python scrapy中添加cookie踩坑记录

    问题发现: 前段时间项目中,为了防止被封号(提供的可用账号太少),对于能不登录就可以抓取的内容采用不带cookie的策略,只有必要的内容才带上cookie去访问. 本来想着很简单:在每个抛出来的Request的meta中带上一个标志位,通过在CookieMiddleware中查看这个标志位,决定是否是给这个Request是否装上Cookie. 实现的代码大致如下: class CookieMiddleware(object): """ 每次请求都随机从账号池中选择一个账号去访

随机推荐