質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

IRC

IRC(Internet Relay Chat)は、インターネットを用いたテキストチャット方式。専用ソフトをインストールすれば、用意されたサーバへ接続しスムーズにログを進めることが可能です。多くのOSで利用でき、多言語にも対応しています。

Q&A

解決済

2回答

1325閲覧

Pythonを用いてのIRC botととの通信ができない

Yuta_for

総合スコア21

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

IRC

IRC(Internet Relay Chat)は、インターネットを用いたテキストチャット方式。専用ソフトをインストールすれば、用意されたサーバへ接続しスムーズにログを進めることが可能です。多くのOSで利用でき、多言語にも対応しています。

0グッド

0クリップ

投稿2020/04/12 07:01

編集2020/04/16 16:22

#エラー概要
IRCとの通信ができない。

詳細

こちらのチュートリアルを基にPythonを用いてのIRCとの通信接続を試みようとしていますが、型違反?と思われるエラーが発生してうまくいきません。

irc

1import socket 2import sys 3 4class IRC: 5 irc = socket.socket() 6 7 def __init__(self): 8 self.irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 10 def send(self, chan, msg): 11 self.irc.send("PRIVMSG" + chan + " " + msg + "n") 12 13 def connect(self, server, channel, botnick): 14 # defines the socket 15 print("connecting to:" + server) 16 self.irc.connect((server, 6667)) # connects to the server 17 self.irc.send("USER " + botnick + " " + botnick + " " + botnick + " :This is a fun bot!n") # user authentication 18 self.irc.send("NICK " + botnick + "n") 19 self.irc.send("JOIN " + channel + "n") # join the channel 20 21 def get_text(self): 22 text=self.irc.recv(2040) # receive the text 23 24 if text.find('PING') != -1: 25 self.irc.find('PONG' + text.split()[1] + 'rn') 26 return text

bot

1from irc import * 2import os 3import random 4 5channel = "#testit" 6server = "irc.freenode.net" 7botnick = "reddity" 8 9irc = IRC() 10irc.connect(server, channel, botnick) 11 12while 1: 13 text = irc.get_text() 14 print(text) 15 16 if "PRIVMSG" in text and channel in text and "hello" in text: 17 irc.send(channel, "HEllo!")

bot.pyを実行した所、以下のエラーが発生しました。

Python

1/home/yuta/Desktop/work/python/PycharmProjects/TestPJ/venv/bin/python /home/yuta/Desktop/work/python/PycharmProjects/TestPJ/networking/bot.py 2connecting to:irc.freenode.net 3Traceback (most recent call last): 4 File "/home/yuta/Desktop/work/python/PycharmProjects/TestPJ/networking/bot.py", line 10, in <module> 5 irc.connect(server, channel, botnick) 6 File "/home/yuta/Desktop/work/python/PycharmProjects/TestPJ/networking/irc.py", line 17, in connect 7 self.irc.send("USER " + botnick + " " + botnick + " " + botnick + " :This is a fun bot!n") # user authentication 8TypeError: a bytes-like object is required, not 'str' 9 10Process finished with exit code 1

TypeError: a bytes-like object is required, not 'str'
↑はbyte型で指定しないといけないという意味はなんとなくわかるのですが、具体的にどこを修正すればよろしいのかイマイチ理解できておりません。

わかる人がいましたらご教授お願いいたします。

2020/4/26追記
指摘点を基に修正しましたが新たなエラーが出ました。

irc

1import socket 2import sys 3 4class IRC: 5 irc = socket.socket() 6 7 def __init__(self): 8 self.irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 10 def send(self, chan, msg): 11 self.irc.send("PRIVMSG " + chan + " " + msg + "\n") 12 13 def _send_raw(self, line, encoding="utf-8"): 14 self.irc.send(line.encode(encoding) + b"\r\n") 15 16 def connect(self, server, channel, botnick): 17 # defines the socket 18 print("connecting to:" + server) 19 self.irc.connect((server, 6667)) # connects to the server 20 self.irc.send("USER " + botnick + " " + botnick + " " + botnick + " :This is a fun bot!\n") # user authentication 21 self.irc.send("NICK " + botnick + "\n") 22 self.irc.send("JOIN " + channel + "\n") # join the channel 23 24 def get_text(self): 25 text=self.irc.recv(2040) # receive the text 26 27 if text.find(b'PING') != -1: 28 self._send_raw('PONG' + text.split()[1]) 29 return text

bot

1from irc import * 2import os 3import random 4 5channel = "#testit" 6server = "irc.freenode.net" 7botnick = "reddity" 8 9irc = IRC() 10irc.connect(server, channel, botnick) 11 12while 1: 13 text = irc.get_text() 14 print(text) 15 16 if "PRIVMSG " in text and channel in text and "hello" in text: 17 irc.send(channel, "HEllo!")

Python

1/home/yuta/Desktop/work/python/PycharmProjects/TestPJ/venv/bin/python /home/yuta/Desktop/work/python/PycharmProjects/TestPJ/networking/bot.py 2Traceback (most recent call last): 3 File "/home/yuta/Desktop/work/python/PycharmProjects/TestPJ/networking/bot.py", line 10, in <module> 4 irc.connect(server, channel, botnick) 5AttributeError: 'IRC' object has no attribute 'connect' 6 7Process finished with exit code 1 8

connect属性を持っていないとエラーがでました。
irc.pyの該当属性を入れ子にしてタブをずらしたことで属性を見つけられなくなったと推測できたのですが、この場合botの呼び出しの引数をどのようにirc.pyの方へ渡せば良いのでしょうか?
わかる方がいらしたらぜひアドバイスをお願い致します。

2020/04/16追記
指摘を基に修正したところ新たなエラーがでました。

irc

1import socket 2import sys 3 4class IRC: 5 irc = socket.socket() 6 7 def __init__(self): 8 self.irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 10 def send(self, chan, msg): 11 self.irc._send_raw("PRIVMSG " + chan + " " + msg + "\n") 12 13 def _send_raw(self, line, encoding="utf-8"): 14 self.irc._send_raw(line.encode(encoding) + b"\r\n") 15 16 def connect(self, server, channel, botnick): 17 # defines the socket 18 print("connecting to:" + server) 19 self.irc.connect((server, 6667)) # connects to the server 20 self.irc._send_raw("USER " + botnick + " " + botnick + " " + botnick + " :This is a fun bot!\n") # user authentication 21 self.irc._send_raw("NICK " + botnick + "\n") 22 self.irc._send_raw("JOIN " + channel + "\n") # join the channel 23 24 def get_text(self): 25 text=self.irc.recv(2040) # receive the text 26 27 if text.find(b'PING') != -1: 28 self._send_raw('PONG' + text.split()[1]) 29 return text

Python

1/home/yuta/Desktop/work/python/PycharmProjects/TestPJ/venv/bin/python /home/yuta/Desktop/work/python/PycharmProjects/TestPJ/networking/bot.py 2connecting to:irc.freenode.net 3Traceback (most recent call last): 4 File "/home/yuta/Desktop/work/python/PycharmProjects/TestPJ/networking/bot.py", line 10, in <module> 5 irc.connect(server, channel, botnick) 6 File "/home/yuta/Desktop/work/python/PycharmProjects/TestPJ/networking/irc.py", line 20, in connect 7 self.irc._send_raw("USER " + botnick + " " + botnick + " " + botnick + " :This is a fun bot!\n") # user authentication 8AttributeError: 'socket' object has no attribute '_send_raw' 9 10Process finished with exit code 1 11

クラスsocketが_send_raw属性を持たないとエラーが出ていますが、なぜクラスsocketがここで出てくるのかよくわかりません。
IRCクラス内の属性だと思ったのですが、この辺の仕組みがよく理解できていないように思います。
エラーの原因がわかりましたらご教授お願いいたします。

2020/4/17追記

Python

1/home/yuta/Desktop/work/python/PycharmProjects/TestPJ/venv/bin/python /home/yuta/Desktop/work/python/PycharmProjects/TestPJ/networking/bot.py 2connecting to:irc.freenode.net 3b':barjavel.freenode.net NOTICE * :*** Looking up your hostname...\r\n' 4Traceback (most recent call last): 5 File "/home/yuta/Desktop/work/python/PycharmProjects/TestPJ/networking/bot.py", line 16, in <module> 6 if "PRIVMSG " in text and channel in text and "hello" in text: 7TypeError: a bytes-like object is required, not 'str' 8 9Process finished with exit code 1

bot

1from irc import * 2import os 3import random 4 5channel = "#testit" 6server = "irc.freenode.net" 7botnick = "reddity" 8 9irc = IRC() 10irc.connect(server, channel, botnick) 11 12while 1: 13 text = irc.get_text() 14 print(text) 15 16 if "PRIVMSG " in text and channel in text and "hello" in text: 17 irc.send(channel, "HEllo!")

呼び出す側のbotで型エラーがおきました。

strをbyteに直す必要がありますが、どこを指しているのか不明です。
自分では全然検討もつかなくものすごく申し訳ないですが、わかる人がいましたらご教授お願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

python

1class IRC: 2 # ここは不要です 3 # irc = socket.socket() 4 5 def __init__(self): 6 self.irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 8 def send(self, chan, msg): 9 self._send_raw("PRIVMSG " + chan + " " + msg + "\n") 10 11 def _send_raw(self, line, encoding="utf-8"): 12 # 文字列→バイト型にしてから送信 13 self.irc.send(line.encode(encoding)) 14 15 def connect(self, server, channel, botnick): 16 # defines the socket 17 print("connecting to:" + server) 18 self.irc.connect((server, 6667)) # connects to the server 19 self._send_raw("USER " + botnick + " " + botnick + " " + botnick + " :This is a fun bot!\n") # user authentication 20 self._send_raw("NICK " + botnick + "\n") 21 self._send_raw("JOIN " + channel + "\n") # join the channel 22 23 def get_text(self): 24 text=self.irc.recv(2040) # receive the text 25 26 if text.find(b'PING') != -1: 27 self._send_raw('PONG' + text.split()[1]) 28 return text

修正箇所

  • _send_raw メソッドの中身
  • self.irc._send_raw -> self._send_raw
  • もう一点追加で、末尾の改行文字が2重に追加されるので

self.irc.send(line.encode(encoding)) の b'\r\n' を外しました。

コードの修正箇所を少なくする為。_send_raw内のを変更しましたが、
呼び出し側で追加するか、_send_raw内で追加するか、どちらか片方で良いです。


追記

python

1 2from irc import * 3import os 4import random 5 6channel = "#testit" 7server = "irc.freenode.net" 8botnick = "reddity" 9 10irc = IRC() 11irc.connect(server, channel, botnick) 12 13while 1: 14 text = irc.get_text().decode("utf-8") 15 print(text) 16 17 if "PRIVMSG" in text and channel in text and "hello" in text: 18 irc.send(channel, "HEllo!") 19

変更点:
text = irc.get_text().decode("utf-8")

text がバイト型の場合

  • b"PRIVMSG" in text
  • b"hello" in text
  • とできますが、 channel in text の channel は 文字列なので変換が必要

但し、irc.send は文字列を要求されるので。元のtextを文字列に変換するようにしました。
エンコードは固定で utf-8 としてます。

投稿2020/04/16 15:11

編集2020/04/16 23:31
teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yuta_for

2020/04/16 23:10

度々ありがとうございます。 申し訳ない事にまだ解決出来なくて本文中に追記いたしました。 textとchannelに問題があるのでしょうか?
teamikl

2020/04/16 23:22

ここも受信したデータは文字列ではなくバイト型になってるので、 型を合わせる為に b"RRIVMSG" b"hello" のようにします
teamikl

2020/04/16 23:27

channel in text も型を合わせる必要がありました。 もう一点修正、回答に追記します
Yuta_for

2020/04/17 04:24

できました! 何度もアドバイスくださりありがとうございます!
guest

0

参考もとにしたコードが Python2.x 系のものなのだと思います。
2.x -> 3.x への大きな変更で、文字列とバイト列を区別するようになったので、
文字コードを指定してバイト型に変換する必要があります。

  • また、エラーの内容とは別の部分ですが、行末の "n" や "rn" に関しては、
    エスケープシーケンスが消えてしまってるので "\n", "\r\n" に。
  • PONGを返すところはtypoで、find ではなく send です。
  • "PRIVMSG " <- スペースが必要です

修正方法の一例を挙げると。

  • b"..." はバイト型のリテラル
  • "..." の文字列は、.encode("utf-8") で変換。

IRCプロトコルの規定に文字コードの規約はなかったので、
文字コードはサーバーの設定に依存します。
(freenodeは未テストなので解りません) クライアントの設定確認utf-8 でした。
例えば、他の日本語のサーバーならiso-2022-jp等がありました。

diff

1- self.irc.find('PONG ' + text.split() [1] + 'rn') 2+ self.irc.send(b'PONG ' + text.split()[1].encode("utf-8") + b'\r\n')

送受信は全部変更する必要があるので、メソッドにしておくとよいです。

# send() メソッドは使われていたので、 # メソッド名は、何か適当に内部で使われるもの風な名前に。 def _send_raw(self, line, encoding="utf-8"): self.irc.send(line.encode(encoding) + b"\r\n") # 呼び出し側: 例) self._send_raw('PONG ' + text.split()[1])

受信するデータもバイト型になっています。
値チェック等は文字列と同じ find が使えますが、
バイト型のデータが要求されます。

diff

1- if text.find('PING') != -1: 2+ if text.find(b'PING') != -1:

投稿2020/04/12 13:45

編集2020/04/12 18:50
teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yuta_for

2020/04/15 16:18

ご回答ありがとうございます。 ご指摘頂いた箇所を基に修正したら新たにエラーが発生しましたので、もしよろしければこちらの問題点もお願いしてもよろしいでしょうか?
teamikl

2020/04/15 17:50 編集

socketのconnect と区別が必要ですが、 IRCクラス内の def connect が全体的にインデントが1段階ずれてます。 _send_raw内部で定義するようになってるので、他の関数と同じ位置に合わせると直るはずです。 タブ文字を使うと見かけは同じでも、タブ幅4や8だったりして、 インデントが合ってないことも有るので、(Pythonでは)基本インデントはスペースにして下さい。 追記: 他の self.irc.send を直接呼んでいる箇所も、TypeErrorとなるので、 _send_raw を用いるように修正が必要です。
Yuta_for

2020/04/16 14:47

何度もご指摘ありがとうございます。 大変申し訳ないですが、私の理解が足りておらず新しいエラーへの対処ができずまた助けが必要になりました。 何度もお願いしてしまい大変恐縮なのですが、こちらもご確認いただけますでしょうか?
teamikl

2020/04/16 14:50

最初に修正した箇所と同じ PONGの所と同様で self.irc._send_raw -> self._send_raw です
teamikl

2020/04/16 14:51

IRCクラスの中と外にircという変数があるので混同されたのだと思います。 irc = IRC() これは IRCクラスのインスタンス class IRC内の self.irc = socket.socket() これはソケット
teamikl

2020/04/16 14:58

それから、 def _send_raw の中身も見直してください。 ここはソケットに対してバイト型のデータを送るので self.irc.send です 他の箇所は、直接ソケットにデータを送らず、_send_raw に文字列を渡して 文字列 -> バイト型変換してから送るようにします
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問