目次
サンプル・プログラム
searchcafewin.msi | インストーラ |
bin/searchcafewin.exe | 実行プログラム本体 |
bin/cwebpage.dll bin/libcurl.dll | 実行時に必要になるDLL |
bin/etc/help.chm | ヘルプ・ファイル |
sour/searchcafewin.cpp | ソース・プログラム |
sour/resource.h | リソース・ヘッダ |
sour/resource.rc | リソース・ファイル |
sour/application.ico | アプリケーション・アイコン |
sour/mystrings.cpp | 汎用文字列処理関数など(ソース) |
sour/mystrings.h | 汎用文字列処理関数など(ヘッダ) |
sour/pahooGeocode.cpp | 住所・緯度・経度に関わるクラス(ソース) |
sour/pahooGeocode.hpp | 住所・緯度・経度に関わるクラス(ヘッダ) |
sour/apikey.cpp | APIキーの管理(ソース) |
sour/apikey.hpp | APIキーの管理(ヘッダ) |
sour/WebView2.h | WebView2に関わるヘッダ |
sour/event.h | WebView2用インターフェース(ヘッダ) |
sour/event.cpp | WebView2用インターフェース(ソース) |
sour/pahooWebView2.cpp | WebView2に関わる関数(ソース) |
sour/pahooWebView2.hpp | WebView2に関わる関数(ヘッダ) |
sour/makefile | ビルド |
バージョン | 更新日 | 内容 |
---|---|---|
1.0.1 | 2024/08/31 | 使用ライブラリ更新 |
1.0.0 | 2024/04/29 | 初版 |
バージョン | 更新日 | 内容 |
---|---|---|
1.8.0 | 2024/05/03 | getMyPath()をapikey.appのgetMyPath()関数に変更 |
1.7.0 | 2024/04/27 | Edge対応に伴いデバッグ用コードを廃棄 |
1.6.0 | 2023/07/02 | getPointsGSI()メソッド追加 |
1.5 | 2022/09/03 | デバッグコード埋め込み |
1.4 | 2021/05/01 | makeMapLeaflet() 引数追加 |
バージョン | 更新日 | 内容 |
---|---|---|
1.2.0 | 2024/05/06 | getModulePath() 追加 |
1.12 | 2021/01/31 | readWebContents() 引数post追加 |
1.11 | 2020/10/17 | htmlspecialchars() 追加 |
1.1 | 2020/10/17 | GetVersion2()追加,readWebContents() 引数ua追加 |
1.01 | 2020/10/03 | setClipboardData() bug-fix |
バージョン | 更新日 | 内容 |
---|---|---|
1.0.0 | 2024/04/27 | 初版 |
バージョン | 更新日 | 内容 |
---|---|---|
2.0.0 | 2024/04/29 | createSetAPIkey, processSetAPIkey に統合 |
1.0 | 2020/09/30 | 初版 |
使用ライブラリ
また、地図表示にWebブラウザ・コントロールを利用するため "WebView2Loader.dll" を利用する。jchv / webview2-in-mingw からダウンロードできる。
リソースの準備
Eclipse を起動し、新規プロジェクト searchcafewin を用意する。
ResEdit を起動し、resource.rc を用意する。
Eclipse に戻り、ソース・プログラム "searchcafewin.cpp" を追加する。
リンカー・フラグを -Wl,--enable-stdcall-fixup -mwindows -lgdiplus -static -lstdc++ -lgcc -lwinpthread -lcurl -lssl "C:\(libcurl-x64.dllのフォルダ)\libcurl-x64.dll" "C:\(WebView2Loader.dllのフォルダ)\WebView2Loader.dll" に設定する。
また、コマンド行パターンを ${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS} -lole32 -loleaut32 -luuid にすること。
MSYS2 コマンドラインからビルドするのであれば、"makefile" を利用してほしい。
解説:定数など
43: // 定数など ==================================================================
44: #define MAKER "pahoo.org" //作成者
45: #define APPNAME "searchcafewin" //アプリケーション名
46: #define APPNAMEJP "喫茶店を検索" //アプリケーション名(日本語)
47: #define APPVERSION "1.0.1" //バージョン
48: #define APPYEAR "2024" //作成年
49: #define REFERENCE "https://www.pahoo.org/e-soul/webtech/cpp01/cpp01-17-01.shtm" //参考サイト
50:
51: //ListViewItemの最大文字長:変更不可
52: #define MAX_LISTVIEWITEM 259
53:
54: //ヘルプ・ファイル
55: #define HELPFILE ".\\etc\\help.chm"
56:
57: //デフォルト保存ファイル名
58: #define SAVEFILE "stationsearchwin.csv"
59:
60: //ホットペッパーグルメWebサービス APIキー名称
61: #define LABEL_HOTPEPPER_API "ホットペッパーAPIキー"
62: //ホットペッパーグルメWebサービス APIキー保存ファイル名
63: #define FNAME_HOTPEPPER_API "HotpepperAPIkey"
64: //ホットペッパーグルメWebサービス APIキー取得ページ
65: #define URL_HOTPEPPER_API "https://webservice.recruit.co.jp/register"
66: //ホットペッパーグルメWebサービス 検索ジャンルID:カフェ・スイーツ
67: #define HOTPEPPER_GENRE "G014"
68:
69: //マップID
70: #define MAP_ID "map_id"
71: //地図の大きさ
72: #define MAP_WIDTH 550 //地図の幅(ピクセル)
73: #define MAP_HEIGHT 320 //地図の高さ(ピクセル)
74: //経度・緯度(初期値)
75: #define DEF_LONGITUDE 139.766667
76: double Longitude = DEF_LONGITUDE;
77: #define DEF_LATITUDE 35.681111
78: double Latitude = DEF_LATITUDE;
79: //地図拡大率(初期値)
80: #define DEF_ZOOM 13
81: int Zoom = DEF_ZOOM;
82: //地図の種類(初期値)
83: #define DEF_MAPTYPE "GSISTD"
84: string Maptype = DEF_MAPTYPE;
ホットペッパー グルメサーチAPI
URL |
---|
https://webservice.recruit.co.jp/hotpepper/gourmet/v1/ |
フィールド名 | 要否 | 内 容 |
---|---|---|
key | 必須 | APIキー |
lat | 必須 | 緯度 |
lng | 必須 | 経度 |
range | 必須 | 検索範囲 1: 300m 2: 500m 3: 1000m (初期値) 4: 2000m 5: 3000m |
datum | 任意 | world: 世界測地系、tokyo: 旧日本測地系。初期値は world。 |
genre | 任意 | お店ジャンルコード。本プログラムでは定数HOTPEPPER_GENREで指定。 |
count | 任意 | 検索結果の最大出力データ数を指定します。初期値:10、宰相:1、最大100。 |
format | 任意 | レスポンス形式。初期値:xml。xml または json または jsonp。 |
解説:ホットペッパーグルメWebサービスの呼び出し
392: /**
393: * ホットペッパー グルメサーチAPI から必要な情報を配列に格納する
394: * @param double latitude 緯度(世界測地系)
395: * @param double longitude 経度(世界測地系)
396: * @param int range 検索範囲(1:300m,2:500m,3:1000m,4:2000m,5:3000m)
397: * @param string genre ジャンルID
398: * @return int ヒット数/(-1):エラー発生
399: */
400: int pahooHotpepper::getResults_Hotpepper(double latitude, double longitude, int range, string genre) {
401: //ホットペッパー グルメサーチAPI呼び出し
402: char lat[SIZE_BUFF + 1], lng[SIZE_BUFF + 1], rng[SIZE_BUFF + 1];;
403:
404: if (range <= 0 || range > 5) {
405: setError(_SW("検索範囲が間違っています"));
406: return (-1);
407: }
408:
409: snprintf(lat, SIZE_BUFF, "%.5f", latitude);
410: snprintf(lng, SIZE_BUFF, "%.5f", longitude);
411: snprintf(rng, SIZE_BUFF, "%d", range);
412: this->webapi = "http://webservice.recruit.co.jp/hotpepper/gourmet/v1/?key=" + HotpepperAPIkey + "&lat=" + (string)lat + "&lng=" + (string)lng + "&range=" + (string)rng + "&genre=" + (string)genre;
413:
414: //ホットペッパー グルメサーチAPI 応答
415: string contents = "";
416: bool res = readWebContents(this->webapi, UserAgent, &contents);
417: if (res == FALSE) {
418: setError(_SW("ホットペッパー グルメサーチAPI の接続エラーが発生しました"));
419: return (-1);
420: }
421:
422: //配列の初期化
423: for (int i = 0; i < __SIZE_PPOINTS; i++) {
424: this->Cafes[i].id = 0;
425: this->Cafes[i].name = this->Cafes[i].address = L"";
426: this->Cafes[i].latitude = this->Cafes[i].longitude = 0.0;
427: this->Cafes[i].url = this->Cafes[i].photo = "";
428: this->Cafes[i].open = this->Cafes[i].close = L"";
429: this->Cafes[i].wifi = this->Cafes[i].budget = L"";
430: }
431:
432: //XML読み込み
433: int cnt = 0;
434: try {
435: std::stringstream ss;
436: ss.str("");
437: ss << contents;
438: ptree pt;
439: xml_parser::read_xml(ss, pt);
440:
441: //応答チェック
442: if (optional<string>str = pt.get_optional<string>("results.results_returned")) {
443: int n = stoi(str.get());
444: if (n <= 0) {
445: return 0;
446: }
447: } else {
448: setError(_SW("ホットペッパー グルメサーチAPI の応答エラーが発生しました"));
449: return (-1);
450: }
451:
452: //XML解釈
453: try {
454: for (auto it : pt.get_child("results")) {
455: if (cnt >= __SIZE_PPOINTS) {
456: break;
457: }
458: //読み飛ばし
459: if (it.first != "shop") {
460: continue;
461: }
462: //識別子
463: this->Cafes[cnt].id = cnt + 1;
464: //店名
465: if (optional<string>name = it.second.get_optional<string>("name")) {
466: this->Cafes[cnt].name = _UW(name.value());
467: }
468: //住所
469: if (optional<string>address = it.second.get_optional<string>("address")) {
470: this->Cafes[cnt].address = _UW(address.value());
471: }
472: //緯度
473: if (optional<string>lat = it.second.get_optional<string>("lat")) {
474: this->Cafes[cnt].latitude = stod(lat.value());
475: }
476: //経度
477: if (optional<string>lng = it.second.get_optional<string>("lng")) {
478: this->Cafes[cnt].longitude = stod(lng.value());
479: }
480: //営業時間
481: if (optional<string>open = it.second.get_optional<string>("open")) {
482: this->Cafes[cnt].open = _UW(open.value());
483: }
484: //定休日
485: if (optional<string>close = it.second.get_optional<string>("close")) {
486: this->Cafes[cnt].close = _UW(close.value());
487: }
488: //PC向けURL
489: if (optional<string>url = it.second.get_optional<string>("urls.pc")) {
490: this->Cafes[cnt].url = url.value();
491: }
492: //写真URL
493: if (optional<string>photo = it.second.get_optional<string>("photo.pc.s")) {
494: this->Cafes[cnt].photo = photo.value();
495: }
496: //ディナー予算
497: if (optional<string>budget = it.second.get_optional<string>("budget.average")) {
498: this->Cafes[cnt].budget = _UW(budget.value());
499: }
500: //Wi-Fi有無
501: if (optional<string>wifi = it.second.get_optional<string>("wifi")) {
502: this->Cafes[cnt].wifi = _UW(wifi.value());
503: }
504: cnt++;
505: }
506: //XML解釈エラー
507: } catch(ptree_bad_path& e) {
508: setError(_SW("ホットペッパー グルメサーチAPI の検索エラーが発生しました"));
509: return (-1);
510: }
511:
512: //読み込みエラー
513: } catch(xml_parser_error& e) {
514: setError(_SW("ホットペッパー グルメサーチAPI の接続エラーが発生しました"));
515: return (-1);
516: }
517: contents.clear();
518:
519: /** debug
520: cout << "cnt = " << cnt << endl;
521: for (int i = 0; i < cnt; i++) {
522: cout << _WS(this->Cafes[cnt].name) << endl;
523: }
524: **/
525:
526: return cnt;
527: }
Boost C++ライブラリ の property_tree にある xml_parser を利用する。
今回も、cURL を使って応答情報を変数に代入し、ストリーミングを使ってxmlパーサーに流し込んでやる。
共通手順、モジュールなど
- C++ 開発環境の準備:ぱふぅ家のホームページ
- C++ 開発環境の準備 -MSYS2編-
- WiX によるWindowsインストーラー作成:ぱふぅ家のホームページ
- C++ でダイアログボックスを使う
- C++ でイベント駆動型アプリを作る
- 解説:ニュース一覧作成
C++ で Googleニュース検索 - 解説:検索結果をCSVファイルに保存
C++ で Googleニュース検索 - 解説:クリップボード
C++ でパスワード生成機を作る - 解説:APIキーの管理
C++ で直近の地震情報を取得する - 解説:WebView2
C++ で直近の地震情報を取得する - 解説:解説:マップ表示用HTML生成
C++ で直近の地震情報を取得する 参考サイト
- グルメサーチAPI:ホットペッパー
- PHPでホットペッパーを利用して喫茶店を検索する
(この項おわり)
「PHPでホットペッパーを利用して喫茶店を検索する」で作ったPHPプログラムをC++に移植したものである。
(2024年8月31日)使用ライブラリ更新