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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Q&A

解決済

2回答

2822閲覧

Python2.7でXPath(lxml使用)の抽出結果を最終的にstr型(シフトJIS)のリストで得たい

lemonade

総合スコア10

Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

0グッド

0クリップ

投稿2016/04/24 16:50

編集2016/04/25 12:05

Python2.7でlxmlのXPathを使って取得した抽出結果のデータを
最終的にシフトJISの文字列型(str型)のリストの形で得たいのですが、
どうもうまくいかず困っています。

xpathを使って抽出されたデータが格納される変数は、
print文で表示可能で一見するとunicode型のリストの形ではあるものの、
中に格納されているデータを組み込み関数のtypeで確認してみると、
「<type 'lxml.etree._ElementUnicodeResult'>」や
「<class 'lxml.etree._ElementStringResult'>」という形式になっています。
これらをstr型(シフトJIS)に変換できないものかと
自分なりにいろいろ試行錯誤してみましたがうまくいかず、
web検索して調べてみても良い解決策が見つかりませんでした。

一体どうすればXPathの抽出結果を
シフトJISの文字列型(str形式)のリストの形で
取得できるでしょうか?

ちなみに、当方の環境は、OSがWindows7(64bit)、
Pythonは2.7.10(32bit)です。

Python

1# coding: cp932 2 3import lxml.html 4 5url = 'http://www.adobe.com/jp/#' 6xpath_query = '//a/text()' 7list = lxml.html.parse(url).xpath(xpath_query) 8 9print type(list) #<type 'list'> 10print list #リストの中身は確認可能。unicode型の文字列のリスト? 11print list[236] #UnicodeEncodeError: 'cp932' codec can't encode character u'\xed' in position 0:illegal multibyte sequence 12print list[236].encode('cp932','ignore') #何も表示されない 13print type(list[236]) #<type 'lxml.etree._ElementUnicodeResult'> 14print type(list[237]) #<class 'lxml.etree._ElementStringResult'>

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

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

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

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

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

guest

回答2

0

ベストアンサー

結論から言うと、一部に限定すればcp932への変換は可能かもしれませんが、
すべてをcp932に変換しようとしているのであれば無理だと思います。

質問のURLにあるページにはハングルなどが含まれており、
cp932でエンコードできないものが有るようです。
質問にあるプログラムのlist[236]がまさにハングルであるので、
エンコードに失敗しているのだと思います。

python

1# coding: cp932 2 3import lxml.html 4 5url = 'http://www.adobe.com/jp/#' 6xpath_query = '//a/text()' 7l = lxml.html.parse(url, parser=lxml.html.HTMLParser(encoding='utf-8')).xpath(xpath_query) 8 9 10print l[236].encode('cp932', 'ignore') # == (ignoreなので失敗した文字を無視している) 11print l[236].encode('cp932', 'replace') # == ?? (replaceだと空の文字列でないことはわかる) 12print l[236].encode('utf-8') # == 한국 (ハングルを扱える、例えばutf-8ならばエンコード可能)

別件で質問と関係ないことで、何か意図があるのでしたら申し訳ないのですが、
listはpythonの組み込み関数なので変数名に用いるのは避けたほうがいいと思います。

投稿2016/04/26 10:26

編集2016/04/29 01:07
toko

総合スコア144

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

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

lemonade

2016/04/28 19:31

ご回答ありがとうございました。 また、ご返信遅れてしまい申し訳ございません。 「list」が組み込み関数であるという点につきましては、 恥ずかしながら知りませんでした。 勉強になりました。ありがとうございました。 以後、気をつけたいと思います。 さて、l[236]がハングルであるというご指摘についてですが、 当方の環境では、まず、ご回答いただいたコードを実行すると、 コマンドプロンプト上にはどうやっても(# coding: cp932の部分を変えてみたり、 ソースファイル自体の文字コードを変えてみたり、 .encode('utf-8') の部分を変えてみたりなどいろいろ試しましたが) 「テュツ閉愿ェツオツュ」といった文字化けしたものが表示されてしまいますが、 htmlファイルを見て確認するかぎりではたしかにハングルですね。 ただ、その前のl[235]ではソースを確認する限りでは「日本」となっていて、 これは言うまでもなく日本語です。で、これを試しに表示させようとすると、 これもエラーはでないものの表示はどうやっても化けてしまいます。 (「.encode('utf-8')」でエラーなし文字化け表示、「.encode('cp932')」では 「UnicodeEncodeError: 'cp932' codec can't encode character u'\xe6' in position 0:illegal multibyte sequence」となります。) これをまともに表示させることはできないのでしょうか? というか、toko様はどんな環境なんでしょう? それと、よくわからないのが、このhtmlファイルは23行目に 「<meta charset="utf-8">」とある通り、文字コードは「utf-8」なわけですが、 例えば、urlの部分を文字コードが同じ「utf-8」なwebサイト 「http://www.yahoo.co.jp」として、要素の数は236個もないので、 一の位の6を削ってテキトーに「l[23]」として、 「print l[23].encode('cp932')」を実行すると「Y!モバゲー」と 一切文字化けせずにきちんと日本語が表示されます。 この違いは一体何なのでしょうか? 自分なりに調べたり考えたりしてみましたが、 いまだにさっぱりわかりません。
toko

2016/04/29 03:41 編集

文字化けですが、次の2点が原因だと思います。 1. コマンドプロンプトのエンコーディング設定 2. parse時のエンコーディングの扱い 1について、コマンドプロンプトのデフォルトのエンコーディングはcp932なので、 設定等していないかぎりにおいてはutf-8は文字化けすると思います。 chcp 65001 を実行した後(エンコーディングをutf-8に設定した後) であれば文字化けしないと思います。 2について、parse時にutf-8で読み込めていなかったようです。 lxml.html.parseの引数にparserの指定をしてみてください(回答に反映しました)。 なぜ、 "http://yahoo.co.jp"はparserの指定をしなくてもutf-8で読み込むのに、 "http://www.adobe.com/jp/#"は指定をしないといけないのか、 についてですが、両者HTML中でのエンコーディングの指定が若干違います。 この問題については "HTML encoding and lxml parsing"(http://stackoverflow.com/questions/15302125/html-encoding-and-lxml-parsing) に同様の質問がありますが、lxml側の問題だと思います。
lemonade

2016/04/29 13:21

ご回答ありがとうございます。 なるほど、同じutf-8でもエンコーディングの指定が若干違うことで、 挙動が変わってくるのですね。 そこまで考えが及びませんでした。 さて、コマンドプロンプトでの表示についてですが、 早速、ご指示どおり「chcp 65001」をコマンドプロンプトで実行し、 ご呈示いただいたコードを実行してみましたが、 残念ながら、当方の環境では文字化けしてしまい、 正常に表示させることはできませんでした。 そこで、webで調べてみたところ、以下の記事が見つかり、 コマンド「chcp 65001」を実行してコマンドプロンプトの文字エンコードを UTF-8にしたけど日本語表示で苦戦したお話 http://piyopiyocs.blog115.fc2.com/blog-entry-830.html それを参考にコマンドプロンプトのフォントをMSゴシックに変更した後で、 一旦終了→再度立ち上げて、「chcp 65001」を実行して再度試してみました。 しかし、試しにテキストエディタで「日本」とだけ書いて、 それを文字コード「utf-8」で保存した「utf-8.txt」というutf-8のサンプルファイルを typeコマンドでコマンドプロンプト上で日本語表示させることには成功したものの、 ご呈示いただいたコードについてはよくわからない謎のエラーがでてダメでした。 E:\>type utf-8.txt 日本 E:\>test.py ?? ���本Traceback (most recent call last): File "E:\test.py", line 11, in <module> print l[235].encode('utf-8') IOError: [Errno 2] No such file or directory ちなみにこの状態ででここから再度「chcp 932」を実行して元に戻し、 再度、スクリプトを実行すると、「IOError」は出ないものの、 今度はやはり文字化けしてしまいます。 E:\>test.py ?? 譌・譛ャ しかし、この状態で最後の行の部分を 「print l[236].encode('utf-8')」から 「print l[235].encode('cp932')」へと書き換えてみたところ、 E:\>test.py ?? 日本 「日本」の部分がうまく表示されました! 最後にparse時のエンコーディングの扱いの件ですが、 「lxml.html.HTMLParser(encoding='utf-8')」と、 この部分で文字コードを指定できたのですね。 勉強不足でした。 この部分がとても重要で、この時点できちんと文字コードを 指定して読み込まないと、どうやらその後で何をやっても、 もうどうにもならないようですね。 この度はご丁寧な回答をいただき、本当にありがとうございました。 おかげ様で助かりました。
guest

0

解決しませんでした。

投稿2016/04/25 12:18

lemonade

総合スコア10

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問