2012/10/11

Recent entries from same category

  1. C言語から分かりやすいAPIで扱える JSON パーサ「cJSON」
  2. C++ で STL フレンドリに扱えるJSONパーサ「json.hpp」
  3. SSE を使わなくても HTML エスケープはある程度速くできる。
  4. glib を使ったマイクロフレームワーク「balde」
  5. ODBC 接続なアプリケーションの開発が楽になる C++ ライブラリ nanodbc

タイトルなげーーーーーーーーーーー!
プロキシ環境下でしか動きませんが、使いたい人は勝手に書き換えて下さい。
boost::bind 使わずラムダだけでやってんの、オレオレルールだから気にした奴は負け。
#define _WIN32_WINNT 0x0501
#include <iostream>
#include <string>
#include <sstream>
#include <system_error>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/regex.hpp>
#include <boost/foreach.hpp>
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
#include <boost/property_tree/json_parser.hpp>

using namespace boost::asio;
using namespace boost::asio::ip;
using namespace boost::property_tree;
using namespace boost::system;

int
main(int argc, char* argv[]) {
  if (argc == 1) {
    std::cerr << "usage: " << argv[0] << " [words]" << std::endl;
    return -1;
  }

  // リクエストする URL を作る
  std::string get_url =
    "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=";

  for (int i = 1; i < argc; i++) {
    std::string arg = argv[i];
    BOOST_FOREACH(auto c, arg) {
      if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
          (c >= '0' && c <= '9') ||
          c == '-' || c == '_' || c == '.' || c == '~') {
        get_url += c;
      } else if (c == ' ') {
        get_url += '+';
      } else {
        std::stringstream ss;
        ss << "%" << std::hex << std::setw(2) <<
          std::setfill('0') << (int) (c & 0xff);
        get_url += ss.str();
      }
    }
  }

  // HTTP_PROXY 環境変数からホスト名とポート番号を得る
  std::string http_proxy = std::getenv("HTTP_PROXY");
  boost::regex pattern("^(?:http://)?([^/]+):([0-9]+)");
  boost::match_results<std::string::const_iterator> it;
  if (!regex_search(http_proxy, it, pattern)) {
    std::cerr << "プロキシを使っていません" << std::endl;
    return -1;
  }

  io_service service;
  tcp::resolver resolver(service);

  // ホスト名から名前解決を行う
  tcp::resolver::query resolver_query(
    std::string(it[1].first, it[1].second), // ホスト名
    std::string(it[2].first, it[2].second)  // ポート番号
  );

  std::string data;
  resolver.async_resolve(
    resolver_query,
    [&](const error_code& ec, tcp::resolver::iterator it) {
      if (ec) {
        std::cerr << ec.message() << std::endl;
      } else {
        // プロキシに接続する
        tcp::socket socket(service);
        socket.async_connect(
          it->endpoint(),
          [&](const error_code& ec) {
            if (ec) {
              std::cerr << ec.message() << std::endl;
            } else {
              // プロキシに GET 命令を送信する
              std::string query = "GET ";
              query += get_url;
              query += " HTTP/1.0\r\n\r\n";

              async_write(
                socket,
                buffer(query.c_str(), query.size()),
                [&](const error_code& ec, std::size_t len) {
                  if (ec) {
                    std::cerr << ec.message() << std::endl;
                  } else {
                    boost::array<char1024> buf;
                    std::stringstream ss;
                    // HTTP/1.0 なので切断までループ
                    while (socket.is_open()) {
                      socket.async_read_some(
                        buffer(buf),
                        [&](const error_code& ec, std::size_t len) {
                          if (ec) {
                            socket.close();
                          } else if (len == 0) {
                            socket.close();
                          } else {
                            ss << std::string(buf.data(), len);
                            buf.assign(0);
                          }
                        });
                      service.run_one();
                    }
                    data = ss.str();
                    // ヘッダを取り除く
                    std::size_t pos = data.find("\r\n\r\n");
                    if (pos != std::string::npos) {
                      data = data.substr(pos + 4);
                    }
                  }
                });
              service.run_one();
            }
          });
        service.run_one();
      }
    });
  service.run_one();

  if (!data.empty()) {
    // 結果で得られた JSON をパースする
    std::stringstream ss(data);
    ptree pt;
    read_json(ss, pt);

    if (pt.get<int>("responseStatus") == 200) {
      // 結果配列でループしながら表示
      ptree& results = pt.get_child("responseData.results");
      BOOST_FOREACH(const ptree::value_type& result, results) {
        std::string url = result.second.get<std::string>("url");
        std::string title = result.second.get<std::string>("titleNoFormatting");
        std::cout << url << std::endl << "  " << title << std::endl;
      }
    }
  }
  return 0;
}

blog comments powered by Disqus