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)です。
# coding: cp932
import lxml.html
url = 'http://www.adobe.com/jp/#'
xpath_query = '//a/text()'
list = lxml.html.parse(url).xpath(xpath_query)
print type(list) #<type 'list'>
print list #リストの中身は確認可能。unicode型の文字列のリスト?
print list[236] #UnicodeEncodeError: 'cp932' codec can't encode character u'\xed' in position 0:illegal multibyte sequence
print list[236].encode('cp932','ignore') #何も表示されない
print type(list[236]) #<type 'lxml.etree._ElementUnicodeResult'>
print type(list[237]) #<class 'lxml.etree._ElementStringResult'>
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+3
結論から言うと、一部に限定すればcp932への変換は可能かもしれませんが、
すべてをcp932に変換しようとしているのであれば無理だと思います。
質問のURLにあるページにはハングルなどが含まれており、
cp932でエンコードできないものが有るようです。
質問にあるプログラムのlist[236]
がまさにハングルであるので、
エンコードに失敗しているのだと思います。
# coding: cp932
import lxml.html
url = 'http://www.adobe.com/jp/#'
xpath_query = '//a/text()'
l = lxml.html.parse(url, parser=lxml.html.HTMLParser(encoding='utf-8')).xpath(xpath_query)
print l[236].encode('cp932', 'ignore') # == (ignoreなので失敗した文字を無視している)
print l[236].encode('cp932', 'replace') # == ?? (replaceだと空の文字列でないことはわかる)
print l[236].encode('utf-8') # == 한국 (ハングルを扱える、例えばutf-8ならばエンコード可能)
別件で質問と関係ないことで、何か意図があるのでしたら申し訳ないのですが、
list
はpythonの組み込み関数なので変数名に用いるのは避けたほうがいいと思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
解決しませんでした。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.35%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/04/29 04: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!モバゲー」と
一切文字化けせずにきちんと日本語が表示されます。
この違いは一体何なのでしょうか?
自分なりに調べたり考えたりしてみましたが、
いまだにさっぱりわかりません。
2016/04/29 10:35 編集
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側の問題だと思います。
2016/04/29 22: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')」と、
この部分で文字コードを指定できたのですね。
勉強不足でした。
この部分がとても重要で、この時点できちんと文字コードを
指定して読み込まないと、どうやらその後で何をやっても、
もうどうにもならないようですね。
この度はご丁寧な回答をいただき、本当にありがとうございました。
おかげ様で助かりました。