💡
ヤマト運輸「送り状発行システムB2クラウド」のAPIを開発してパッケージを公開した
python 3.10系では動作しません。(パッケージのSSLの仕様変更によるもの)
python 3.9.16で動作するのを確認しています。
結論
ヤマト運輸さんの「送り状発行サービスB2クラウド」のAPIパッケージをPythonで開発して公開しました。
動機:APIがなくて不便だった
- データのやり取りは基本CSV
- シールに印刷してDMに貼る
シールを貼りに時間がかかる。直接印刷する方式は提供されていない。 - 宛先データに不備があるとリジェクトされる
自動補正の機能はない。
なのでAPIを開発しました
- データの送受信はAPI経由で
- 伝票毎にイメージが分割されるので、直接DMに印刷可能になった
- 宛先を郵便番号、都道府県、市区、町村・番地に分割する
ちょっと宣伝
住所を都道県、市区、町、番地、ビル名に仕分ける機能は、自社開発した住所を正規化するサービスAddressianを使っています。
APIの機能一覧
b2cloud
function | 機能 |
---|---|
login | ヤマトビジネスメンバーズにログインして、sessionを返します。以降のほぼ全てのfunctionの引数として必要です。 |
get_history | 発行済み伝票の履歴を取得します。paramsに検索クエリを指定できます。 |
get_history_all | 発行済み伝票の履歴を取得します。伝票はB2クラウド上に最大90日間保持されるようです。 |
get_history_deleted | 削除済みに移された履歴を取得します。 |
put_tracking | 配送状況を更新・取得します。get_historyでは、配送状況は更新されません。 |
post_new_checkonly | 伝票情報に不備がないかチェックして、エラーまたはOKのfeedを返します。 |
post_new | 新規に伝票を登録します。伝票チェックを行うpost_new_checkonlyでOKとなった戻り値です。 |
check_shipment | post_new_checkonlyの結果から必要情報だけを取得します。単体用 |
check_shipment | post_new_checkonlyの結果から必要情報だけを取得します。リスト用 |
get_new | 発行されていない保存済みの伝票情報を取得します。paramsに検索クエリを指定できます。 |
delete_new | 発行されていない保存済みの伝票情報を削除します。削除された伝票情報は元に戻せません。 |
print_issue | 伝票を印刷してPDFで取得します。新規と再発行とも共通です。新規は印刷されると履歴に所属が移ります。 |
put_history_delete | 伝票を履歴から削除します。display_flg=0にする |
put_history_display | 削除された伝票を履歴に戻します。display_flg=1にする |
get_dm_number_print | DMの送り状番号一覧を印刷します。 |
search_history | 発行済み伝票の履歴の検索クエリのうち、よく使うパラメータを引数にした関数です。 |
b2cloud.utilities
function | 機能 |
---|---|
get_postal | B2クラウドの郵便番号情報を取得します。 |
create_dm_shipment | DM用の送り状情報を生成します。 |
create_empty_shipment | 空の送り状情報を生成します。 |
split_pdf_dm | DMの送り状PDF(1ページあたり8伝票)を1伝票毎に分割します。 |
split_pdf_nekopos | ネコポスの送り状PDF(1ページあたり6伝票)を1伝票毎に分割します。 |
choice_postal | 郵便情報のうち、住所に一番ちかい郵便情報を選択します。 |
get_address_info | 住所を郵便番号、都道府県、市区、町村+番地、ビル・マンション等に分割します。住所正規化サービスAddressianのAPIキーが必要です。 |
インストール
pip install b2cloud
コード例
履歴の取得
import b2cloud
import b2cloud.utilities
session = b2cloud.login('your customer_code', 'your customer_password')
dm = b2cloud.search_history(session, service_type='3')
for entry in dm['feed']['entry']:
print(entry['shipment']['tracking_number'], entry['shipment']['consignee_name'])
新規に伝票を作成し、データに不備がないかチェックする
# 伝票情報を生成する
shipment = b2cloud.utilities.create_dm_shipment(
shipment_date='2022/12/24',
consignee_telephone_display='00-0000-0000',
consignee_name='テスト',
consignee_zip_code='8900053',
consignee_address1='鹿児島県',
consignee_address2='鹿児島市',
consignee_address3='中央町10',
consignee_address4='キャンセビル6階',
consignee_department1='インターマン株式会社'
)
# データに不備がないかチェックする
res = b2cloud.check_shipment(session, shipment)
print(res)
e.g.
{'success': True, 'errors': []}
伝票の新規保存
# shipmentsをpost_new_checkonlyを通す
checked_feed = b2cloud.post_new_checkonly(session, [shipment])
# 伝票情報をB2クラウドに保存する
res = b2cloud.post_new(session, checked_feed)
保存した伝票をDM形式で印刷し各伝票毎にPDFファイルに保存する
# 保存済みのDM伝票を取得
dm_feed = b2cloud.get_new(session, params={'service_type':'3'})
# DM伝票形式(1シート8枚)で印刷
dm_pdf = b2cloud.print_issue(session,'3', dm_feed)
# 1伝票毎に分割する
pdfs = b2cloud.utilities.split_pdf_dm(dm_pdf)
for i in range(len(pdfs)):
with open(f'dm_{i}.pdf', 'wb') as f:
f.write(pdfs[i])
住所を伝票情報に変換する
実行する前に住所正規化サービスAddressian(https://addressian.netlify.app/)のAPI Keyを取得してください。
Googleアカウントがあれば数秒で取得できます。
consignee_address = b2cloud.utilities.get_address_info(
session=session,
addressian_api_key='______apikey_______',
address='鹿児島市中央町10キャンセビル6F'
)
print(consignee_address)
e.g.
{
"consignee_zip_code": "8900053",
"consignee_address1": "鹿児島県",
"consignee_address2": "鹿児島市",
"consignee_address3": "中央町10",
"consignee_address4": "キャンセビル6F"
}
今回開発したパッケージは公開しています
github レポジトリ(https://github.com/interman-corp/b2cloud)
pypi b2cloud (https://pypi.org/project/b2cloud/)
Discussion
素晴らしいコンテンツです。
発払いの伝票をA5やA4で、pdfで取得することもできますか?
ありがとうございます。
print_issueのprint_typeパラメータを指定してください。
'm':A4マルチ、 'm5':A5マルチ
print_typeに3以外を指定すると以下のようなエラーが出ます。
service_typeを0にしてみたのですが状況は変わりません。
ちなみに、pythonのバージョンは3.9.7です。
dm_pdf = b2cloud.print_issue(session,'m5', dm_feed)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/b2cloud/init.py", line 273, in print_issue
if 'tracking_number' in entry_feed['feed']['entry'][0]['shipment']:
KeyError: 'shipment'
DM以外の伝票は、shipmentの必須項目が多くなります。
■ b2cloud.post_new_checkonly(session, [shipment])の返す内容を確認してください。
不備があるとエラー箇所が含まれて返ってきます。
下記が初払いで最低限必要な情報の設定内容です。
# 空の伝票情報を生成します
shipment = b2cloud.utilities.create_empty_shipment()
助けになると幸いです。
シングルクォートにハマりましたが、おかげさまで無事pdfファイルを取得できました。
ちなみにサービスタイプ2が代引きでした。
わからないことがありましたら、またよろしくおねがいします。
お役に立てたようでよかったです。
enjoy hacking.:)
お届け予定eメールの設定は以下の部分だと思うのですが、使用するか否かと機種のパラメータをおしえていだだけませんか。0か1では反映されませんでした。
便利に使えるとだんだん欲が出てきてしまって。よろしくお願いします。
"is_using_shipment_post_email": "",
"shipment_post_email_address": "",
"shipment_post_input_device_type": "",
"shipment_post_message": "",
お届け予定メールのパラメータはこちらのようです。
お試しください。
"is_using_shipment_email": "1",
"shipment_email_address": "hogehoge@gmail.com",
"input_device_type": "1", # PC
"shipment_message": "メッセージ",
ありがとうございます。うまく行きました。
UIはFilemakerでapple script経由でshell scriptで動かしています。
ボタン1発でしばらく待っていると送り状のpdfが開いて印刷画面が表示されるのは最高です。
よかったです!
弊社もFilemakerを使い倒しております。
主にDMですが伝票のシール貼りがないだけでも効率が違いますね。喜ばれております。
(宣伝)Addressianをつかうと住所を分割するのがとても簡単になります。
無料アカウントでも100件/月使えるので感想を聞かせてもらえるとうれしいです。
お聞きしたいのですが、ヤマト運輸のAPIを利用しようとおもっていて、PHPで開発しているのですが、認証の部分ではじかれてしまい、困っています。もし、サンプルコードおもちでしたら、ご教授いただけないでしょうか?
githubで公開しておりますので確認いただけますでしょうか。
9月からB2Cloudに変更がありましたが、現在は対応しております。
はじめまして。大変興味深いAPIで、試してみたのですが、b2cloud.loginで、"ログインに失敗しました。"のエラーになります。こちらのAPIは今も有効に使えるでしょうか?今も有効であれば、恐らく私の使用法が間違っていると思うので、もう少しトライしてみようと思います。
B2クラウド側でURLが変更になったようです。バージョンを更新してますので再度トライしてみてください。
ありがとうございます!試してみます。
これまで通り伝票を発行しようとしたらデータチェックのところでエラーになります。
10月1日からヤマトの仕様が変わったのかも知れません。ご確認ください。
以下はターミナルでの対話型で入力した結果です。
res = b2cloud.check_shipment(session, shipment)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/b2cloud/init.py", line 164, in check_shipment
errors = res['feed']['entry'][0].get('error',[])
KeyError: 'entry'
B2クラウドのURLが変わったようです。バージョンを更新していますのでご確認ください。
更新してみたのですが同じエラーが出ます。ファイルのURLは変更されていたので更新は正常と思われます。このページの”新規に伝票を作成し、データに不備がないかチェックする”のサンプルでも試してみましたが同様です。何か他に原因は考えられますか?
確認したところ、さらに仕様が大きく変わったようです。
弊社はB2Cloudをやめてしまったので、対応致しかねます。
申し訳ございません。ソースコードは公開したままにしておきます。
ヤマトのサイトを確認したところURLを含めて仕様が大きく変わったようです。
弊社では、別の会社に移行してしまったので、対応を含めてサポートを打ち切ろうと思います。
悪しからずご了承ください。
3.9.16では動作することを確認しました。python 3.10でSSLの仕様が変わったためです。
同じ環境で実行できる3.9.13でやってみましたが同じエラーでした。
opensslのバージョンも影響しているのかもしれません。
せっかく便利になったと思ったのに残念です。
こちらで動作を確認している環境をお伝えします。
・python 3.9.16 , MAC
こちらは特に何も必要ないです。
まずはpyenv等で新しい環境をつくってお試しください。
・python 3.10.11, MAC
urllib3を1.26.16にダウングレードする必要がありました。
pythonの標準のSSLの仕様変更によるものです。
pyenvで3.9.16を入れてやってみたのですが同じエラーです。
urllb3が2.0.7だったので1.26.16や1.23.13にダウングレードしてみましたが変わらず。
以下はpipdeptreeでの結果ですが、どうでしょう?
pipdeptree -p b2cloud
b2cloud==0.2.0
├── lxml [required: >=4.9.2,<5.0.0, installed: 4.9.3]
├── PyMuPDF [required: >=1.21.1,<2.0.0, installed: 1.23.5]
│ └── PyMuPDFb [required: ==1.23.5, installed: 1.23.5]
└── requests [required: >=2.28.1,<3.0.0, installed: 2.31.0]
├── certifi [required: >=2017.4.17, installed: 2023.7.22]
├── charset-normalizer [required: >=2,<4, installed: 3.3.1]
├── idna [required: >=2.5,<4, installed: 3.4]
└── urllib3 [required: >=1.21.1,<3, installed: 2.0.7]
当方でもpipdeptreeをしてみましたが、差はないようですね。
b2cloud==0.2.0
├── lxml [required: >=4.9.2,<5.0.0, installed: 4.9.3]
├── PyMuPDF [required: >=1.21.1,<2.0.0, installed: 1.23.5]
│ └── PyMuPDFb [required: ==1.23.5, installed: 1.23.5]
└── requests [required: >=2.28.1,<3.0.0, installed: 2.31.0]
├── certifi [required: >=2017.4.17, installed: 2023.7.22]
├── charset-normalizer [required: >=2,<4, installed: 2.0.12]
├── idna [required: >=2.5,<4, installed: 3.4]
└── urllib3 [required: >=1.21.1,<3, installed: 2.0.7]
########
pip freezeもしてみました。
当方のOSはMac OS Venture 13.3です。
b2cloud==0.2.0
certifi==2023.7.22
charset-normalizer==3.3.2
idna==3.4
lxml==4.9.3
pipdeptree==2.13.0
PyMuPDF==1.23.5
PyMuPDFb==1.23.5
requests==2.31.0
urllib3==2.0.7
完全にクリーンなVenturaのシステムを作ってbrewでpyenvを入れて、pyenvで3.9.16を入れて、pipでb2cloudを入れてやってみたのですが、やはり同様のエラーです。
~/.pyenv/versions/3.9.16/lib/python3.9/site-packages/b2cloud/init.py", line 164, in check_shipment
このチェックまでのヤマトのURLのnewb2web-s2をnewb2webに書き換えると通過するのですが、その後の保存あたりでエラーになります。
何か単純な問題のような気もするのですが。
なお、Mavericks、Montereyでも変わらずです。
バージョン0.2.0でURLは変更済みですので、書き換える必要はないと思います。
post_new_checkonlyの結果にエラー(errorフィールド)がないが確認してください。
テストコードを置いておきます
ここでエラーが出ます。
ログインできてないですね。IDとPWをお確かめください。
Webサイト上ではログインできていますか?
--id-- --pw--の部分を書き換える必要があります。(老婆心ながら)
--追記--
ログインのチェックはsession=login()で通っているはずですね。
b2cloudのバージョンが古い気もします。はて・・・
1行づつ入力してチェックしてますが、ログインには問題ありません。
b2cloudも0.20で、ファイルの中身も確認してみましたがヤマトのurlも新しくなっています。
試しにshipmentの必須項目だけでやってみても同じエラーです。
なんでしょう。
認証周りでうちで使ってる認証情報だけでは把握できてない箇所がありそうですね。
確認ですが、ヤマト運輸さんのサイトでは伝票は作れますでしょうか。
こちらではWindows環境でも伝票が作れましたので、別の要因ぽいですね。
ヤマトのサイトでCSVをインポートしてやる方法では伝票は作れます。
請求先コードは電話番号の末尾に−01が付加されたタイプです。
winでもいけるということはos環境の問題ではなさそうですね。
VenturaのOpenSSLは3.1.4ですが、python3xだと1.1.1だったと思うのですが関係ないでしょうか?
SSLの問題であればJSONの応答すらとれませんので、違うかと思います。
エラー内容的には、ログイン後のsessionが切れているようなんですよね。
ライブラリを使って、履歴の一覧はとれますでしょうか?
res = b2cloud.get_history_all(session)
内部的にもGETメソッドなので、ログインができていれば問題ないはずです。
ログイン直後に切られているような感じです。
PCかネットワーク、又はその両方を変えてみて試していただいた方が良さそうですね。
ネットワークやPCを複数変えてますが変わりません。これまでテストしたOSはmacだけですがwin8があるのでやってみます。
見当違いかと思いますが、ログイン直後のsessionを見ると以下のコードが返ってきます。
win8でも同じエラーでした。
原因はアカウントのタイプかもしれません。
返してきているエラーを取得できないんでしょうか?
アカウントの違いがあるとすれば、loginの後リダイレクト先のURLがちがうのかもしれませんね。
GitHubに公開しているソース追っていただくのがよいかとおもいます。
特にlogin関数の部分を1行ずつ追ってみてください。
その際に、戻り値やパラメータがブラウザを使ったログインと相違がないか確認してみてください。
・ Chromeの開発モードでネットワーク、対象のcURLを取得
・ 必要であればcURLコンバーターでpythonに変換
パラメータやヘッダ、クッキーで照合という流れです。
web関連のノウハウが全くないので大変ですが頑張ってみます。
curlで取ってきてawkやsedで整形して使う程度なので。
やはり、リダイレクト先はnewb2web-2ではなくnewb2webでした。
init.pyを全てnewb2webに書き換えると伝票を保存して、それを取得するところまでは動きました。
次のpdfを印刷するところで以下のエラーが出ます。
~/.pyenv/versions/3.9.16/lib/python3.9/site-packages/b2cloud/init.py", line 319, in print_issue
issue_no = json.loads(response.text)['feed']['title']
KeyError: 'title'
なお、実際に伝票が保存されていることは確認しました。
アカウントによってちがうということですね・・・これは開発が困難ですね。
全部のURLを変えて試すしてみるのがよいですかね。
原因がわかりました。
トラッキング番号の頭の3文字が変更されていました。
ここのVMNがUMNに変わっていました。
番号が一杯になると変わるのでしょう。
ひとまず安心です。