• 締切済み

socketを使用したスクリプトがうまく動きません

お世話になります。教えて!gooを初めて利用する者です。 Perlは本などを見ながら何とか動かせるレベルです。 この度、socketを使って他サイトを読み込む実験をしてみたところ、以下のコードでGoogleのトップページは読み込めましたがYahoo!のトップは何度やってもちゃんと読み込めません。 失敗している部分は、相対パス指定になっている部分のようです。 リンクや画像など、「http://www.yahoo.co.jp/~」となるはずのところが、「http://127.0.0.1/~」となってしまっています。 また、LWPモジュールというものも試してみましたが、こちらはGoogleのトップの読み込みも失敗しました。症状は上と同じです。 コードは本や有名サイトからそのまま引用してもダメで、多少いじってもやはりダメでした。 一人で解決するのは限界だと思いましたので、分かる方いらっしゃいましたらご助言をお願いいたします。 (試したコードの例↓) use Socket; $addr = (gethostbyname("www.google.co.jp"))[4]; $name = pack("S n a4 x8", 2, 80, $addr); socket(S, PF_INET, SOCK_STREAM, 0) || die "socket"; connect(S, $name) || die "connect"; binmode(S); select(S); $| = 1; select(STDOUT); print S "GET / HTTP/1.0\r\n\r\n"; while (<S>) { print; } close(S);

  • Perl
  • 回答数5
  • ありがとう数1

みんなの回答

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.5

>ブラウザで閲覧するのに、そんなふうにする必要があるのでしょうか? ブラウザで閲覧する場合と、スクリプトでページや画像を取り込んだ時とごっちゃになっていると思います。 基本的に、勘違いなされていると思います。 自分のホームページに自分が作ったページをアップする場合と、 自分のホームページで動かすスクリプトが他のサイトから持ってきたページが同じディレクトリにあるとしましょう。 他のサイトから持ってきたページというのは、自分が作成してアップしたのと基本的に同じ(区別はつかない)ですよね。 そうしたときに、リンクなどの指定はどうなっているべきか? ということをちょっと考えてみるとよいのではないでしょうか? >もう一度別の場所でも聞いてみて宜しいでしょうか? もちろん私に聞いてみるまでもなくかまいません。 お役に立てなくて申し訳ありません。

oshietechan123
質問者

お礼

サイトを丸ごと取り込むようなスクリプトの場合はディレクトリ構造も再現する必要があるのでしょうが、今問題になっているような処理でそれが必要となると、アクセスする度にサーバー側(http://127.0.0.1/以下)にファイルやフォルダがどんどん溜まっていくことになって、やっぱりおかしいのではないかと思いますが……一人で考えてもそれ以上はよく分かりませんでした。 他の場所で聞いてみることにします。 長々とお世話になり、どうもありがとうございました。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.4

>それをどこに保存すればいいのかという問題が出てくると思うんですが…。 オリジナルのリンクが相対参照で書かれていれば、 それに合わせてやる必要があります。 例えば src="image/img01.jpg" とかなっていれば、 カレントディレクトリのimageフォルダの中に入れてやる必要があります。 >インターネット上のファイル閲覧って、ベースになるURLを与えてやれば、あとはブラウザが自動的にソースを解析してくれて画像やスタイルシート等も読み込まれてくるのではないのでしょうか? それは、その通りです しかし、 相対パス指定になっているリンクや画像を 自サーバーにダウンロードした状態で、元のサーバーパスhttp://www.yahoo.co.jp/ が、補われたりはしません、 相対パスにはそのような情報はないからです。 相対パスで指定してあるので、デフォルトのサーバーパスがhttp://127.0.0.1/ ~ のように補われます。 これはある意味当然だと思いますけど・・ (自サーバーの相対パスで指定した画像が全然別のサーバーパスになってたらおかしいでしょ?)

oshietechan123
質問者

補足

> カレントディレクトリのimageフォルダの中に入れてやる必要があります。 ブラウザで閲覧するのに、そんなふうにする必要があるのでしょうか? 普通にキャッシュフォルダに入るだけかと思っていましたが…。 > 相対パスにはそのような情報はないからです。 LWPモジュールを使った場合ですけど、私の方でも調べてみると、HTTPレスポンスヘッダ内にそのような情報があるようだと分かりました。(Content-Locationとか、Content-Baseとかそのあたり) これがHTMLの<base>タグのように基準のURLとして使われるのかなと思い、Content-Typeと一緒に渡してみたりしたんですけど、実際には何も変わりませんでした。 …というわけで、もうお手上げです。 やっぱり私のところの環境がおかしいのかもしれません。 そろそろ質問してから1週間経ちますので、もう一度別の場所でも聞いてみて宜しいでしょうか? この度はご迷惑をおかけしましてどうもすみませんでした。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

>LWPモジュールを使用する場合も他のファイルを一つずつ読み込まないといけないんでしょうか? 基本的に1つずつGETしなければダメだと思いますが、もしかしたら丸ごとダウンロードできるような指定があるんですかね? 聞いたところによると、w3mir というのがあるらしいです。 http://search.cpan.org/~janl/w3mir-1.0.10/w3mir.PL >リンクのところが「http://127.0.0.1/~」となってしまう原因は何なんでしょうか? ローカルにダウンロードしたHTMLファイルを起動して相対参照になっている画像ファイルをローカルサーバーのリンクアドレスに展開しているというようなかんじなんじゃないかと思います。

oshietechan123
質問者

補足

w3mirっていうのはちょっと違うみたいです。 私はブラウザで普通に表示できないので困っています。 まず目的のHTMLファイルをGETして、それを解析して画像などを1つずつ読み込んだとしても、それをどこに保存すればいいのかという問題が出てくると思うんですが…。 やっぱり「http://127.0.0.1/~」となっている限り、画像等は読み込まれないような気がします。 インターネット上のファイル閲覧って、ベースになるURLを与えてやれば、あとはブラウザが自動的にソースを解析してくれて画像やスタイルシート等も読み込まれてくるのではないのでしょうか?

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

>> それぞれの、画像などの部分は、別に読み込まないといけないです >これは具体的にはどうやるのでしょうか? >ブラウザが自動的にやってくれるのとは違うんですか? ソケットを使って要求しているファイルは、 >print S "GET / HTTP/1.0\r\n\r\n"; で、トップページだけです。 他のファイルが要るなら、そのファイルを要求しなくちゃいけません。 読み込んだトップページを解析して、リンクから必要なファイルを分析して更に要求しなくちゃいけません。 ブラウザはそれ(アドレスで指定したトップページの内容となる画像などのダウンロードとか)を(影で)やっています。

oshietechan123
質問者

補足

そうなんですか…。ちょっと難しそうです。 LWPモジュールを使用する場合も他のファイルを一つずつ読み込まないといけないんでしょうか? 手元の本にはLWPモジュールを使えば簡単にHTTPアクセスできるというようなことが書いてあるので、socketは諦めてそっちを使おうかとも思います。 それにしても、リンクのところが「http://127.0.0.1/~」となってしまう原因は何なんでしょうか?

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

試してみましたが、むしろ、​"www.google.co.jp" が、別のリンクに転送されるので、失敗し、Yahoo! は、そのままでうまくいく。 と思うのですが。。 LWP は、転送(?)を処理してくれるので逆にうまくいく。 >失敗している部分は、相対パス指定になっている部分のようです。 それぞれの、画像などの部分は、別に読み込まないといけないですけど、(ソケットで要求しているのはトップページだけなので)そういうことじゃないですか?

oshietechan123
質問者

補足

ご回答ありがとうございます。 成功するのと失敗するのが逆になっているとは…環境のせいなんでしょうか…。 > それぞれの、画像などの部分は、別に読み込まないといけないですけど これは具体的にはどうやるのでしょうか? ブラウザが自動的にやってくれるのとは違うんですか?

関連するQ&A

  • socketを使って外部のファイルを呼び込む

    $Host = 'abc.hogehoge.co.jp'; $Page = "/test_order.cgi?pass=1234&id=1234' $Addr = (gethostbyname($Host))[4]; $Name = pack("S n a4 x8", 2, 443, $Addr); socket(S, 2, 1, 0); connect(S, $Name); binmode(S); select(S); $| = 1; select(stdout); print S "GET $Page HTTP/1.0\r\n\r\n"; $Data = ''; while (<S>){ $Data = $_; } close(S); print"$Data"; 現在ある決済システムを組み込もうとしております。 上のように外部ホストのアクセスしてパスワードやID、その他あるのですがそれで接続していてもどうにも$Dataに出力されません。 print S "GET $Page HTTP/1.0\r\n\r\n"; とありますが外部ファイルはhtmlファイルではありません。たんなるテキスト文字が出力されるはずです。 直接ブラウザに https://abc.hogehoge.co.jp/test_order.cgi?pass=1234&id=1234' とたたくとテキストが出力されます。 なにかまちがっているのでしょうか? 恐れ入りますがご教授お願いします

    • ベストアンサー
    • CGI
  • socket経由でHTMLを表示

    するために test.pl: #!/usr/local/bin/perl use Socket; $addr=(gethostbyname("www.ndl.go.jp"))[4]; $name=pack("S n a4 x8",2,80,$addr); socket(S,PF_INET,SOCK_STREAM,0); connect(S,$name); binmode(S); select(S);$|=1;select(stdout); print S "GET /index.html HTTP/1.1\n"; print S "Host:www.ndl.go.jp\n\n"; print "Content-type: text/html\n\n"; while(<S>){print;} close(S); をPerlが実行できるプロバイダのスペースにアップして Meのie6ブラウザからtest.plを表示させるとエラーになります どうしたらエラーを回避して "http://www.ndl.go.jp/index.html"(国立国会図書館) を表示することができるでしょうか?

    • ベストアンサー
    • Perl
  • socket通信でレスポンスを受け入れないようにするにはどうすればいいですか?

    socket SOCKET,2,1,0; select((select(SOCKET),$|=1)[0]); connect(SOCKET,pack('Sna4x8',2,80,scalar(gethostbyname('www.test.test')); print SOCKET "GET /test.cgi HTTP/1.1\r\n\r\n"; こんな感じでhttp://www.test.test/test.cgiをリクエストしているのですが、結果がわかっているので、レスポンスが必要ありません。 どうもリクエストが終わると<SOCKET>を実行しないでも勝手にレスポンスをサーバから読み込んでいるみたいです。 (なのでリクエストを送った後、ある程度の時間をおいてオフライン状態にしても<SOCKET>からレスポンスを読み取れます) レスポンスの結果は分かっているので読み込みたくないのですが、どうすればいいのでしょうか?

  • perlのソケット通信について

    perlのソケット通信でwebブラウザーのようなものを製作中なのです。 http://tohoho.wakusei.ne.jp/wwwperl2.htm#socketを参考にしたのですが、 yahooは表示されますが、xrea系のサイトのような特定のサイトが閲覧できず(どちらかというと特定のサイトのみ閲覧できる)、NotFoundかDNSエラーになります。 とほほのWWW入門のサンプルの他に追加する項目などはあるのでしょうか?よろしくお願いします。 現在の構文は以下の通りです browser.cgi 改行コードLF、漢字コードEUC ------------- #! /usr/bin/perl print "Content-type:text/html\n\n"; $addr = (gethostbyname("www.xrea.com"))[4]; $name = pack("S n a4 x8", 2, 80, $addr); socket(S, 2, 1, 0); connect(S, $name); binmode(S); select(S); $| = 1; select(stdout); print S "GET /index.php HTTP/1.0\n\n"; while (<S>) { print; } close(S);

    • ベストアンサー
    • Perl
  • SOCKETで入手したデータを抜き出したい

    他サーバのHTMLから部分的に抜き出したいと思っています。 他サーバのHTMLを表示する所までは出来たのですが、抜き出す所が出来ずに困っています。 私が抜き出そうと、表示のwhile文内を下記に変えた所、何も表示されなくなりました。  if( $_ =~ m/抜き出したい頭のキーワード/ ){ $flag = 1;}  if( $_ =~ m/表示したい尾のキーワード/ ){ $flag = 0;}  if( $flag eq 1){ print $_;} このwhile文内には変数に代入するとどうもNGのようです。 教えてGooの過去ログにも同様の質問があったのですが、 解決に至っていませんでした。ご教示願います。 ↓現在のソースコード ---------------------------- #!/usr/local/bin/perl -w use strict; use Socket; # Socket モジュールを使う # 接続先ホスト名 my $host = 'www.xxxx.co.jp'; # HTTP プロトコルを使う my $port = getservbyname('http', 'tcp'); # ホスト名を、IP アドレスの構造体に変換 my $iaddr = inet_aton($host) or die "$host は存在しないホストです。\n"; # ポート番号と IP アドレスを構造体に変換 my $sock_addr = pack_sockaddr_in($port, $iaddr); # ソケット生成 socket(SOCKET, PF_INET, SOCK_STREAM, 0) or die "ソケットを生成できません。\n"; # 指定のホストの指定のポートに接続 connect(SOCKET, $sock_addr) or die "$host のポート $portに接続できません。\n"; # ファイルハンドル SOCKET をバッファリングしない select(SOCKET); $|=1; select(STDOUT); # WWW サーバに HTTP リクエストを送る print SOCKET "GET /index.html HTTP/1.0\r\n"; print SOCKET "\r\n"; # ヘッダ部分を受け取る while (<SOCKET>){ # 改行のみの行ならループを抜ける m/^\r\n$/ and last; } # ボディ部分を受け取り、表示 while (<SOCKET>){ print $_; }

    • ベストアンサー
    • Perl
  • ソケットの使い方が分からない

    ので動作を見るためにとほほを見て WidnowsMeで x.pl: use Socket; $addr=(gethostbyname("www.ndl.go.jp"))[4]; $name=pack("S n a4 x8", 2, 80, $addr); socket(S,PF_INET,SOCK_STREAM,0); connect(S, $name); binmode(S); select(S); $|=1; select(stdout); print S "GET index.html HTTP/1.0\r\n\r\n"; while(<S>){print;} close(S); を作り perl x.pl を実行すると HTTP/1.1 400 Bad Request Date: Fri, 04 Feb 2005 15:40:15 GMT Server: Apache Content-Length: 226 Connection: close Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>400 Bad Request</title> </head><body> <h1>Bad Request</h1> <p>Your browser sent a request that this server could not understand.<br /> </p> </body></html> が帰ってきました なお http://www.ndl.go.jp/index.html は国立国会図書館のページでブラウザのアドレス欄に入れると正常に見れます どのように修正すればよいでしょうか?

    • ベストアンサー
    • Perl
  • PerlでHTML取得(その前にSocket取得)できない原因について

    下記コードを使い WEBサイトの更新日付を取得したいのですが 実行すると Socket Error:Invalid argument のエラーが表示されソケットの作成に失敗します。 Perlのバージョンは 5.8.0でウィルス対策ソフト停止後のコード実行等対策等を考えて行いましたが状況は改善されません。 よければ、どうしてソケットの作成に失敗するのか教えていただけないでしょうか? 失敗テストケース $host:www.google.co.jp # テストコード # モジュールの使用宣言 use IO::Socket; # URLを入力 $ur1 = <STDIN>; # URLをホスト名とファイルパスに分割 chomp($ur1); if ($ur1 =~ /http:\/\/([^\/]+)(\/.*)/) { $host = $1; $file = $2; } else { die "そのURLには対応していません。\n"; } # ソケットオブジェクト作成 $client_socket = new IO::Socket::INET { PeerAddr => $host, PeerPort => 'http', Proto => 'tcp', TimeOut => '5' }; unless ($client_socket) { print "Socket Error:$!\n"; } # 入力をサーバーに送信 print "$host $file" . "\n"; print $client_socket "GET $file HTTP/1.0\n\n";

    • ベストアンサー
    • Perl
  • WinSockでの通信プログラムがうまくいきません

    WinSockでの通信プログラムがうまくいきません。 使用言語はC++とDirectXです。 ローカルでの通信(ルータを介したパソコン同士)はうまくいくんですが、別の場所にあるPCとの通信ができません。 以下実際に使用している関数です。 関数はマルチスレッドで動かしています。 WSADATA mWsaData; SOCKET mSockYou,mSockI; struct sockaddr_in mAddr; struct sockaddr_in mServer; struct sockaddr_in mClient; void CNetwork::Init(){ int err = WSAStartup( MAKEWORD( 2, 0 ), &mWsaData ); if( err != 0 ){ ERROR_EXIT(); return; } //Socket初期化 mSockI = socket( AF_INET, SOCK_STREAM, 0 ); if( mSockI == INVALID_SOCKET ){ ERROR_EXIT(); return; } mPort = 0; memset( mName, 0, sizeof( mName ) ); } //Server側 void CNetwork::Accept(){ FILE* fp; fopen_s( &fp, "messageLog.txt", "w" ); mAddr.sin_family = AF_INET; mAddr.sin_port = htons( mPort ); mAddr.sin_addr.S_un.S_addr = INADDR_ANY; if( bind( mSockI, (struct sockaddr *)&mAddr, sizeof( mAddr ) ) ) fprintf_s( fp, "bind失敗\n" ); if( listen( mSockI, 10 ) != 0 ) fprintf_s( fp, "listen失敗\n" ); int len = sizeof( mClient ); SOCKET t = accept( mSockI, (struct sockaddr*)&mClient, &len ); if( t == INVALID_SOCKET ) fprintf_s( fp, "Accept失敗\n" ); mSockYou = t; fprintf_s( fp, "Accept終了\n" ); fclose( fp ); } void CNetwork::Connect(){ FILE* fp; fopen_s( &fp, "messageLog.txt", "a" ); fprintf_s( fp, "Connect開始\n" ); //ソケットの設定 mServer.sin_family = AF_INET; mServer.sin_port = htons( mPort ); mServer.sin_addr.S_un.S_addr = inet_addr( mName ); if (mServer.sin_addr.S_un.S_addr == 0xffffffff) { fprintf_s( fp, "hostbynameへ\n" ); struct hostent *host; host = gethostbyname( mName ); if ( host == NULL ) { return false; } mServer.sin_addr.S_un.S_addr = *(unsigned int *)host->h_addr_list[0]; } fprintf_s( fp, "Socketの設定完了\n" ); while( true ){ fprintf_s( fp, "connect()開始\n" ); if( connect( mSockI, (struct sockaddr *)&mServer, sizeof( mServer ) ) == 0 ){ fprintf_s( fp, "Connect完了\n" ); break; } else{ fprintf_s( fp, "Connect失敗\n" ); Sleep(100); } } fprintf_s( fp, "Connect終了\n" ); fclose(fp); } また、ログは下のように出ました。 //サーバ側 Accept失敗 //クライアント側 Connect開始 Socketの設定完了 connect()開始 Connect失敗 ご教授お願いします。

  • Winsockプログラムの初歩的質問(connect()がうまくいかない)

    ソケットの練習をしています。とりあえずconnect()で通信経路を確立するところまでを書いたつもりですが、以下プログラムを実行すると「サーバーソケットに接続失敗」となります。 とりあえずprintf()でチェックしたところsocket()まではうまくいっているようです。 環境:Win2000 , VC++6.0 , LAN接続でDHCP→学内サーバー です。 よろしくお願いします。 #include<winsock2.h> #include<stdio.h> int main() { WSADATA wsaData; struct hostent *host; SOCKET sock1; SOCKADDR_IN name; WSAStartup(2 , &wsaData); host=gethostbyname("www.goo.ne.jp"); //gooのIPアドレスを取得 sock1 = socket(AF_INET,SOCK_STREAM,0); //ソケット生成 /**ここからがあやしい**/ name.sin_port=htons(80); name.sin_addr=*((in_addr *)*host->h_addr_list); if(connect(sock1,(PSOCKADDR)&name,sizeof(name))){ printf("サーバーソケットに接続失敗\n"); return 0; } WSACleanup(); return(0); }

  • 外部シンボルって

    本に載っていた以下のようなサンプルコード #include <stdio.h> #include <winsock.h> void main( void ) { WSADATA wsadata; if ( WSAStartup( 0x0101, &wsadata ) != 0 ) { printf( "WSAStartup の実行に失敗 %d\n", WSAGetLastError()); } int sock; struct sockaddr_in addr; int ret ; struct hostent *hostinfo; unsigned long inetaddress; char *hostname = "localhost"; inetaddress = inet_addr( hostname ); if ( inetaddress == INADDR_NONE ) { hostinfo = gethostbyname( hostname ); if ( hostinfo == 0 ) { // ホスト名解決に失敗 return ; } inetaddress = *(unsigned long *)hostinfo->h_addr_list[0]; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = inetaddress; addr.sin_port = htons(80); sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); ret = connect( sock, (struct sockaddr *)&addr, sizeof addr ); if ( ret < 0 ) { printf( "localhost 80 に接続できなかった" ); return ; } char get[] = "GET /index.html HTTP/1.0\r\n\r\n"; send( sock, get, strlen(get), 0 ); char buf[256]; int n; printf( "recv data\n" ); while ( 1 ) { n = recv( sock, buf, sizeof(buf)-1, 0 ); if ( n <= 0 ) break; buf[ n ] = '\0'; printf( buf ); } closesocket( sock ); WSACleanup(); } をVC++6.0でコンパイルしたのですが sample_client_win.obj : error LNK2001: 外部シンボル "_WSACleanup@0" は未解決です のようなコンパイルエラーが出て実行できません。これはなにが悪いのでしょうか。本に載っているサンプルコードなのでソース自体は間違っていないと思うのですが・・・もしよろしかったらご教授ください。

専門家に質問してみよう