V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
mikulch
V2EX  ›  Python

如何使用 python3+urllib 发送一个 application/json 的请求?

  •  
  •   mikulch · 2016-07-31 11:32:44 +08:00 · 8911 次点击
    这是一个创建于 3037 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用 postman ,拼装好数据后采用 raw+application/json 的格式,发送 Post 请求能够被服务器正常接收。 通过截包工具 charles 工具,看到发出去的请求是 application/json 格式的数据。

    但是采用 python3+urllib ,设置好 http 请求头的 contentType 为 application/json 格式以后,将参数通过 json.dumps 转换为 str 再 encode 成 bytes ,然后通过 openner 对象访问一个连接后,通过截包工具 charles 发现发出去的请求实际上是 application/x-www-form-urlencoded 的格式,请求虽然能成功但是服务器无法解析。

    不太清楚这里内部处理是怎么一回事,不过尝试了很多方法, urllib 的包里我也没有看到能够直接把 dict 格式的数据作为参数的 api 。 postdata 都需要 bytes 格式的数据才行。

    我的代码大概如下:

    
    	head = {
            'Accept': '*/*',
            'Host': 'www.lvtufang.com',
            'Connection': 'keep-alive',
            'Content-Length': '245',
            'Origin': 'http://www.lvtufang.com',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome'
                          '/51.0.2704.103 Safari/537.36',
            'Content-Type': 'application/json',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Referer': 'http://www.lvtufang.com/Account/Login?ReturnUrl=%2FHotel%2FFind',
            'Accept-Language': 'zh-CN,zh;q=0.8',
            'Accept-Encoding': 'gzip, deflate'
        }
        
    		cookie = cookiejar.CookieJar()
            handler = urllib.request.HTTPCookieProcessor(cookie)
            opener = urllib.request.build_opener(handler)
            opener.addheader(head)
            # 其他为了获取 cookie 的各种请求。
            .....
            .....
            .....
            parsed_request_data = json.dumps(self.hotel_search_request_data).encode()
            response = openner.open(self.hotel_search_url, parsed_request_data)
    

    不知道是否有经验的同学能不能帮一下忙。谢谢!

    6 条回复    2016-07-31 18:05:17 +08:00
    SuperFashi
        1
    SuperFashi  
       2016-07-31 12:38:25 +08:00 via Android
    首先我推荐 requests 库。
    看起来是没有问题的,不过有一些小地方问你一下,为啥 head 里面钦定了 Content-Length ,还有你确定后面没有动到 head 吗?推荐你在 post 之前先输出一下 head 。
    matthewgao
        2
    matthewgao  
       2016-07-31 17:30:17 +08:00
    你用的是 HTTPCookieProcessor , Content-Type 并不是 cookie 的一部分
    mikulch
        3
    mikulch  
    OP
       2016-07-31 17:46:28 +08:00
    @SuperFashi
    req = request.Request(self.hotel_search_url, data=parsed_request_data, headers=self.head)
    最后我用这样的方式解决了问题。

    奇怪的是, openner.addheaders 设置了以后,实际上根本没有作用。通过 openner.open 发出去的请求,全部都是带有默认的 http header 的请求。。。实在是不知道原因是什么。
    mikulch
        4
    mikulch  
    OP
       2016-07-31 17:49:51 +08:00
    @matthewgao 我是看了官方文档
    https://docs.python.org/3/library/urllib.request.html
    才这么做的。
    但是官方文档使用的是默认的 openBuilder 。也就是说,使用 httpCookieProcessor 的时候, addheader 实际上并没有生效么。。。
    mikulch
        5
    mikulch  
    OP
       2016-07-31 17:57:33 +08:00
    @SuperFashi sorry
    我又看了一次 使用 openner.open 这个 api 的时候,会自动的生成默认的几个 header 。
    其他的 header 是可以设置的。
    使用 opener.open 这个 api 的时候 content-type 会默认变成 application/x-www-form-urlencoded 。
    matthewgao
        6
    matthewgao  
       2016-07-31 18:05:17 +08:00
    @mikulch 我觉得可能会被覆盖掉,我没有特别细的看 document ,但是看起来你没有操作任何 cookies 相关的,所以是不是用 HTTPHandler 就可以呢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1144 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 18:37 · PVG 02:37 · LAX 10:37 · JFK 13:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.