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

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

新規登録して質問してみよう
ただいま回答率
85.50%
XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Python 3.x

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

Q&A

解決済

1回答

249閲覧

BeautifulSoupでXMLをMySqlに投入するも途中で TypeError: must be str, not NoneType 表示

aoki_monpro

総合スコア45

XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Python 3.x

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

0グッド

0クリップ

投稿2018/01/27 11:01

あるAPI (XML) をBeautifulSoup にて取得しMySqlにインポートしようとしているのですが、

タグの形式が変わるものがあり、処理が停止してしまうので、
知見のある方に打開策をいただければと思います。

対象のAPI (XML、ブラウザ表示時) (抜粋)

■rating中身あり

XML

1 2<item> 3 <name>桜木</name> 4 <rating>3</rating> 5</item> 6

XML

1■Rating中身なし 2 3<item> 4 <name>流川</name> 5 <rating/> 6</item>

BeautifulSoupにてテキスト出力してみると下記のようなタグに変わっていました。

XML

1 2<item> 3 <name>流川</name> 4 <rating></rating> 5</item> 6

エラーメッセージ

Python

1TypeError: must be str, not NoneType 2(SQL文でエラー)

コード

Python

1import urllib.request 2from bs4 import BeautifulSoup 3import pymysql.cursors 4import requests 5 6 7connection = pymysql.connect( 8 host='localhost', 9 port=3306, 10 user='user', 11 password='password', 12 db='test_db', 13 charset='utf8', 14 cursorclass=pymysql.cursors.DictCursor 15) 16 17cursor = connection.cursor() 18 19url = "http://api.url" 20 21html = urllib.request.urlopen(url) 22soup = BeautifulSoup(html,"html5lib") 23 24#print(soup.prettify()) テキスト出力確認用 25 26for item in soup.findAll("item"): 27 name = item.name.string 28 29 30#空の場合は0を入れてみるもうまくいかず・・ 31 if item.rating.string == "": 32 Rating = '0' 33 34 else: 35 Rating = item.rating.string 36 37 sql = "insert into `test_table` (`name`, `rating`) values ('" + name + "','" + rating + "')" 38 39 cursor.execute(sql) 40 result = cursor.fetchall() 41 connection.commit() 42 43connection.close() 44

(テーブル等簡素化しています)

40件中25件ほどまでは問題なくMySqlにインポートされるのですが、
<Rating/> のタグがでてくるとエラーになってしまいます。

ご教授のほど、よろしくお願いいたします。

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

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

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

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

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

jun68ykt

2018/01/27 11:15 編集

こんにちは。質問に追記していただきたい情報として、test_table テーブルの、rating カラムの型が何か知りたいです。より望ましいのは、test_table のテーブル定義があるとよいので、 mysql のコンソールからコマンド SHOW CREATE TABLE test_table; と打って、その結果をコピペして頂けるとなおよいです。
aoki_monpro

2018/01/27 11:38 編集

jun68ykt 様、早速のコメントありがとうございます。テーブルの型ですが、まだテスト中だったこともあり、下記の設定にしておりました。 CREATE TABLE `test_table` ( `name` varchar(255) NOT NULL, `Rating` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 NOT NULL がまずい?でしょうか、、
guest

回答1

0

ベストアンサー

こんにちは。

<rating></rating> のときに、item.rating.stringNoneになりますが、
ある変数xの値が None であるかどうかの判定は

python

1if x is None:

とします。これに合わせて、ご質問の以下の部分

修正前:

python

1for item in soup.findAll("item"): 2 name = item.name.string 3 4 #空の場合は0を入れてみるもうまくいかず・・ 5 if item.rating.string == "": 6 Rating = '0' 7 else: 8 Rating = item.rating.string 9 10 sql = "insert into `test_table` (`name`, `rating`) values ('" + name + "','" + rating + "')"

をたとえば以下のように修正します。(上記で Ratingという変数は、rating がおそらく正しいと思います)

修正後:

python

1for item in soup.findAll("item"): 2 name = item.nameTag.string 3 rating = item.rating.string 4 5 if rating is None: 6 rating = '' 7 8 sql = "insert into `test_table` (`name`, `rating`) values ('" + name + "','" + rating + "')"

上記の場合は、 テーブルの rating カラムには空文字列が入ります。
ですが、空文字列を入れるよりは、 何も入らない(= NULLのまま)ほうがよいならば、
以下のように、 ratingカラムに何も値を入れないSQLにします。

python

1for item in soup.findAll("item"): 2 name = item.nameTag.string 3 rating = item.rating.string 4 5 if rating is None: 6 sql = "insert into `test_table` (`name`) values ('" + name + "')" 7 else: 8 sql = "insert into `test_table` (`name`, `rating`) values ('" + name + "','" + rating + "')"

ただし、この場合は、test_tablerating カラムに NOT NULL制約があると
<rating></rating> の item がテーブルに入らないので、NOT NULL制約を
外します。

もうひとつ指摘すべき点として、ご質問のコードには

python

1name = item.name.string

とありますが、item.namename は、 <name>要素ではなくて、 itemという
BeautifulSoup が提供するXML要素オブジェクトのname属性という意味になって、
item.name"item"という文字列を返します。

そのため、item.name.string という呼び出しは、
AttributeError: 'str' object has no attribute 'string'
となってしまいます。
これを回避するために、

python

1name = item.nameTag.string

または、

python

1name = item.find("name").string

とします。

それと、もう一点、質問にあるコードで、

python

1soup = BeautifulSoup(html,"html5lib")

としているところは、XMLのパースなので

python

1soup = BeautifulSoup(xml,"xml")

としたほうがよいと思います。

上記をふまえて、以下が、私が手元で作成した、ソースの全体です。
(XMLはヒアドキュメントから読み、 SQLは、<rating></rating>のとき、ratingには何も値を入れない
ほうにしています。)

python

1import pymysql.cursors 2from bs4 import BeautifulSoup 3 4connection = pymysql.connect( 5 host='localhost', 6 port=3306, 7 user='root', 8 password='xxxxxxxx', 9 db='xxxxxx', 10 charset='utf8', 11 cursorclass=pymysql.cursors.DictCursor, 12) 13 14cursor = connection.cursor() 15 16xml = """ 17<?xml version="1.0" encoding="UTF-8"?> 18<items> 19 <item> 20 <name>桜木</name> 21 <rating>3</rating> 22 </item> 23 <item> 24 <name>流川</name> 25 <rating/> 26 </item> 27</items> 28""" 29 30soup = BeautifulSoup(xml, "xml") 31 32for item in soup.findAll("item"): 33 name = item.nameTag.string 34 rating = item.rating.string 35 36 if rating is None: 37 sql = "insert into `test_table` (`name`) values ('" + name + "')" 38 else: 39 sql = "insert into `test_table` (`name`, `rating`) values ('" + name + "','" + rating + "')" 40 41 cursor.execute(sql) 42 43connection.commit() 44connection.close()

以上、参考になれば幸いです。

投稿2018/01/27 14:28

編集2018/01/27 15:06
jun68ykt

総合スコア9058

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

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

aoki_monpro

2018/01/27 14:44

jun68ykt様 ありがとうございます!無事MySqlにインポートできました! また細かな修正点もご教授ありがとうございます。 おかげで業務がかなりはかどると思います。 重ねて、ありがとうございました。
jun68ykt

2018/01/27 14:45

解決されたようで、よかったです!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問