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
woshichuanqilz
V2EX  ›  Python

爬虫使用 requests post 抓取汇率失败, 请教原因.

  •  
  •   woshichuanqilz · 2019-10-02 21:14:34 +08:00 · 4893 次点击
    这是一个创建于 1878 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想从这个网站上获取人民币对美元的汇率, http://forex.jrj.com.cn/

    跟踪调试的过程,发现是由这个链接获取的, http://quote1.fx168.com/jrj/CurrencyConvert/ajaxpro/CurrencyConvert.ConvertJrj,jrj.ashx

    如下是我的代码 header, formdata 复制的原请求,

    # -*- coding: utf-8 -*-
    import requests
    import json
    
    def get_exchange():
        headers = {
            'Accept': '*/*',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'en,zh-CN;q=0.9,zh;q=0.8,en-US;q=0.7,ja;q=0.6',
            'Ajax-method': 'Calculate',
            'Connection': 'keep-alive',
            'Content-Length': '56',
            'Content-Type': 'application/x-www-form-urlencoded',
            'Host': 'quote1.fx168.com',
            'Origin': 'http://quote1.fx168.com',
            'Referer': 'http://quote1.fx168.com/Jrj/CurrencyConvert/ConvertJrj3.aspx',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36',
        }
        testUrl = 'http://quote1.fx168.com/jrj/CurrencyConvert/ajaxpro/CurrencyConvert.ConvertJrj,jrj.ashx'
        submit_data = {"moneys": "1", "start": "美元", "end": "人民币"}
        response = requests.post(testUrl, headers=headers, data=submit_data)
        print(response.content)
    
    
    if __name__ == '__main__':
        get_exchange()
    

    但是输入的结果却不对,

    b'"word m"'

    不知道我的代码问题在哪里, 请教一下。

    20 条回复    2019-10-03 14:34:00 +08:00
    Trim21
        1
    Trim21  
       2019-10-02 21:20:58 +08:00
    因为 post 过去的 body 实际上不是‘application/x-www-form-urlencoded’而是 json 字符串

    response = requests.post(testUrl, headers=headers, data=json.dumps(submit_data))
    ClericPy
        2
    ClericPy  
       2019-10-02 21:35:28 +08:00   ❤️ 2
    楼上说的比较明白了
    然后那个 requests 的参数 data 可以直接用 json=

    平时我处理这种请求, 基本上先复制请求的 CurlString, 然后 curlparse 出来, 必要时候 clean request

    ```python
    from torequests.utils import curlparse
    import requests

    requests_args = curlparse(r'''curl 'http://quote1.fx168.com/jrj/CurrencyConvert/ajaxpro/CurrencyConvert.ConvertJrj,jrj.ashx' -H 'Origin: http://quote1.fx168.com' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: zh-CN,zh;q=0.9' -H 'Ajax-method: Calculate' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: */*' -H 'Referer: http://quote1.fx168.com/Jrj/CurrencyConvert/ConvertJrj3.aspx' -H 'Connection: keep-alive' -H 'DNT: 1' --data $'{"moneys": "100", "start": "美元", "end": "人民币"}\r\n' --compressed --insecure''')
    print(requests_args)
    # {'url': 'http://quote1.fx168.com/jrj/CurrencyConvert/ajaxpro/CurrencyConvert.ConvertJrj,jrj.ashx', 'headers': {'Origin': 'http://quote1.fx168.com', 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Ajax-Method': 'Calculate', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*', 'Referer': 'http://quote1.fx168.com/Jrj/CurrencyConvert/ConvertJrj3.aspx', 'Connection': 'keep-alive', 'Dnt': '1'}, 'data': b'{"moneys": "100", "start": "\xe7\xbe\x8e\xe5\x85\x83", "end": "\xe4\xba\xba\xe6\xb0\x91\xe5\xb8\x81"}\\r\\n', 'method': 'post'}
    r = requests.request(**requests_args)
    print(r.text)
    # "665.14"


    ```
    ClericPy
        3
    ClericPy  
       2019-10-02 21:35:47 +08:00
    这见鬼的排版... 想删帖都...
    woshichuanqilz
        4
    woshichuanqilz  
    OP
       2019-10-02 22:29:01 +08:00
    @Trim21 我修改之后获取到的数据是 1.91, 而不是 6.65, 这个问题在哪?
    woshichuanqilz
        5
    woshichuanqilz  
    OP
       2019-10-02 22:37:49 +08:00
    @Trim21 还有就是为什么 指定的是 application/x-www-form-urlencoded 传过去的确实 json 的数据呢?
    Trim21
        6
    Trim21  
       2019-10-02 22:38:17 +08:00
    @woshichuanqilz 大概是美元和人民币几个汉字的编码问题,我也不清楚到底应该是什么编码,你可以从 2 楼的那个 requests_args 里面直接复制出来然后单纯修改 moneys 来用
    woshichuanqilz
        7
    woshichuanqilz  
    OP
       2019-10-02 22:38:18 +08:00
    @ClericPy 获取结果是成功的谢谢, 我研究下。
    为什么你不用 requests 解决呢?
    Trim21
        8
    Trim21  
       2019-10-02 22:40:29 +08:00   ❤️ 1
    @woshichuanqilz #5 是因为网站就是这么干的,至于他们为什么要这么干我们就不知道了……
    woshichuanqilz
        9
    woshichuanqilz  
    OP
       2019-10-02 22:41:42 +08:00
    @ClericPy 我的意思是用 curlparse 的你这种写法优视在哪?
    woshichuanqilz
        10
    woshichuanqilz  
    OP
       2019-10-02 22:41:55 +08:00
    @Trim21 谢谢
    Trim21
        11
    Trim21  
       2019-10-02 23:28:50 +08:00
    @woshichuanqilz #10 刚发现这个请求体不是标准的 json- -
    这么写就成功了
    response = requests.post(
    testUrl,
    headers=headers,
    data='{"moneys": "1", "start": "美元", "end": "人民币"}'.encode()
    )
    Trim21
        12
    Trim21  
       2019-10-02 23:40:24 +08:00
    没弄明白这个网站是怎么构造出这个请求体的,直接拼接字符串么
    ClericPy
        13
    ClericPy  
       2019-10-03 09:31:15 +08:00
    @woshichuanqilz 仔细看看那不就是用的 requests 库吗
    我之所以用 curlparse, 还不是让你看看它的原始请求体是什么, 解析成 requests 库可以用的 dict, 那就是最完整的请求
    203x
        14
    203x  
       2019-10-03 10:35:03 +08:00 via iPhone   ❤️ 1
    可以使用 汇率查询的免费 api
    https://fixer.io/
    snoopygao
        15
    snoopygao  
       2019-10-03 12:48:07 +08:00
    '{"moneys": "1", "start": "美元", "end": "人民币"}'.encode('utf-8')
    Hopetree
        16
    Hopetree  
       2019-10-03 13:45:34 +08:00
    @ClericPy curlparse 这种操作好有点骚啊,原来还可以这样玩
    TangMonk
        17
    TangMonk  
       2019-10-03 14:11:16 +08:00 via iPhone
    搞外汇?
    ClericPy
        18
    ClericPy  
       2019-10-03 14:29:43 +08:00
    @Hopetree 没啥操作啊.. 就是把 CurlString 转 dict, 因为平时老是遇到漏填的参数, 后来直接全带上算了
    后来自己也写出来了个 clean request 的, 就是把非必要参数过滤掉, 也就可以用最简参数发请求
    ClericPy
        19
    ClericPy  
       2019-10-03 14:32:22 +08:00
    @Trim21 他们用的是正经 json, 可能是你用法不对, 带中文部分不能直接 encode, 要么 json.dumps 把非 ascii 的转 unicode, 要么直接用 json= 参数, 放个 dict
    你直接 encode 不一定对方要什么编码, 所以 json 库才有个 ensure_ascii 参数
    ClericPy
        20
    ClericPy  
       2019-10-03 14:34:00 +08:00
    @woshichuanqilz 你说的明明指定 form 却传 json, 可以看看 requests 源码, 发到服务器的时候, 就算 form dict 也会转成 bytes 的


    莫名三连了... 已回复的没法 append 或者 edit 真淡腾...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2401 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 15:49 · PVG 23:49 · LAX 07:49 · JFK 10:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.