PycURLでHTTPリクエストあれこれ

pythonでHTTPリクエストを送信するには...requests? 
いえいえ、PycURLだってあります。
細かくいろいろあれこれするときはPycURLだよねって人、気持ちわかります :smile: 
たまには趣向を変えましょう。

ここではPycURLを使っていろいろいろするためのやり方を書いていきます。

# PycURLとは...

http://pycurl.io/
https://pypi.python.org/pypi/pycurl



PycURLはlibcurlのためのPythonインタフェースです。大概requestsでもおんなじことができる(はず)。

# インストール

pip でインストールします。

```
$ pip install pycurl
```

http://pycurl.io/docs/latest/index.html#installation にインストールの説明があります。

サーバには https://gist.github.com/TakesxiSximada/d2792ef0b6ef2947402cca008b0323ea を使います。server.pyをダウンロードして以下を実行してください。

```
$ python server.py
```

# メソッドの設定

REST APIのメソッドを指定してリクエストを送信します。

## GET

```get_example_default.py
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.perform()
```

実行結果

デフォルトの挙動ではrespose bodyは標準出力に書き出されます。

```
$ python get_example_default.py
OK

```

メソッドを指定しない場合はGETになります。

メソッド名を明示的に指定したい場合は Curlオブジェクトに pycurl.CUSTOMREQUESTを設定します。

```get_example.py
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.setopt(pycurl.CUSTOMREQUEST, 'GET')
curl.perform()
```

## POST

```
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.setopt(pycurl.CUSTOMREQUEST, 'POST')
curl.perform()
```

POSTFIELDを設定した場合はデフォルトでPOSTになります。

```
import urllib.parse
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
field_data = urllib.parse.urlencode({'key': 'value'})
curl.setopt(pycurl.POSTFIELDS, field_data)
curl.perform()
```

## PUT

```
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.setopt(pycurl.CUSTOMREQUEST, 'PUT')
curl.perform()
```

## PATCH

```
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.setopt(pycurl.CUSTOMREQUEST, 'PATCH')
curl.perform()
```

## HEAD

```
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.setopt(pycurl.CUSTOMREQUEST, 'HEAD')
curl.perform()
```

## DELETE

```
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.setopt(pycurl.CUSTOMREQUEST, 'DELETE')
curl.perform()
```

## OPTIONS

```
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.setopt(pycurl.CUSTOMREQUEST, 'OPTIONS')
curl.perform()
```

# 詳細情報の表示

pycurl.VERBOSEをTrueで設定すると実行時の詳細情報を取得できます。

```
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.setopt(pycurl.VERBOSE, True)
curl.perform()
```

実行結果

```
$ python verbose.py
* Rebuilt URL to: http://127.0.0.1:8000/
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: PycURL/7.43.0 libcurl/7.43.0 OpenSSL/1.0.2d zlib/1.2.8
Accept: */*

* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: BaseHTTP/0.6 Python/3.5.0
< Date: Sat, 21 May 2016 08:26:41 GMT
<
OK
* Closing connection 0
```

# User Agentの変更

pycurl.USERAGENTでUserAgentを設定できます。

```set_ua.py
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.setopt(pycurl.VERBOSE, True)
curl.setopt(pycurl.USERAGENT, 'yay (^-^)/~')
curl.perform()

```

実行結果

```
$ python set_ua.py
* Rebuilt URL to: http://127.0.0.1:8000/
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: yay (^-^)/~
Accept: */*

* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: BaseHTTP/0.6 Python/3.5.0
< Date: Sat, 21 May 2016 08:37:27 GMT
<
OK
* Closing connection 0
```

## UserAgentはfake-userangetを使うと楽かも。。。

UserAgentを設定するときはいつもfake-useragetを使っているので一応書いておきます。

https://pypi.python.org/pypi/fake-useragent

### インストール

```
$ pip install fake-useragent
```

### PycURLにfake-useragentを使ってChromeのUserAgentを設定する

fake_useragent.UserAgent().chrome でchromeのUAが取得できます。

```set_ua_fakeua.py
import pycurl
import fake_useragent

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://127.0.0.1:8000')
curl.setopt(pycurl.VERBOSE, True)

ua = fake_useragent.UserAgent()
curl.setopt(pycurl.USERAGENT, ua.chrome)
curl.perform()
```

実行結果

```
$ python set_ua_fakeua.py
* Rebuilt URL to: http://127.0.0.1:8000/
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/4E423F
Accept: */*

* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: BaseHTTP/0.6 Python/3.5.0
< Date: Sat, 21 May 2016 08:43:20 GMT
<
OK
* Closing connection 0

```

# 分割ダウンロード

ファイルを途中からダウンロードしたりしたいこと...ありますよねー。
あるでしょ?
あるんですよ。
うん、あるある。

pycurl.RESUME_FROMを設定すると設定したbyte以降からダウンロードできます。
resumeはサーバ側が対応してないとダメなので、gistのデータを途中からダウンロードしてみます。

```resume.py
import pycurl

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'https://gist.githubusercontent.com/TakesxiSximada/d2792ef0b6ef2947402cca008b0323ea/raw/82d677309084d66247a15ce1640bac44a4b23248/server.py')
curl.setopt(pycurl.VERBOSE, True)
curl.setopt(pycurl.RESUME_FROM, 100)
curl.perform()
```

# プログレスバーの表示

プログレスバーは progressbar パッケージを使うと楽なのでそれを使ってみます。
https://pypi.python.org/pypi/progressbar

## インストール

```
$ pip install progressbar
```

## 簡単なprogressbarを表示

```progress.py
import io
import pycurl
import progressbar


class PluggableProgress:
    def __init__(self, progress_plugin):
        self.progress_plugin = progress_plugin

    def __call__(self, total_to_download, total_downloaded,
                 total_to_upload, total_uploaded):
        if total_to_download:
            percent = int(total_downloaded / total_to_download * 100)
            self.progress_plugin.update(percent)

progress_plugin = progressbar.ProgressBar(max_value=progressbar.UnknownLength)
progress = PluggableProgress(progress_plugin)


fp = io.BytesIO()
curl = pycurl.Curl()
curl.setopt(pycurl.URL, '大きめのファイルのURL')  # noqa
curl.setopt(pycurl.NOPROGRESS, 0)
curl.setopt(pycurl.PROGRESSFUNCTION, progress)
curl.setopt(pycurl.WRITEDATA, fp)
curl.perform()
progress_plugin.finish()
```