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

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

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

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

XPath(XML Path)

XML Path Language (XPath; XMLパス言語)は、マークアップ言語 XML に準拠した文書の特定の部分を指定する言語構文の事をいいます。XPathはXMLとは別の構文を使用します。XMLドキュメントの抽象、論理ストラクチャ上で動作します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Scrapy

Scrapyは、Pythonで開発されたオープンソースソフトウェアです。スクレイピングという、Webサービスから必要な情報を取り出したり自動操作をしたりする技術を使うものです。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

4回答

5453閲覧

Python, Scrapyでtd内の複数要素を抽出したい

fukazume

総合スコア78

Python 3.x

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

XPath(XML Path)

XML Path Language (XPath; XMLパス言語)は、マークアップ言語 XML に準拠した文書の特定の部分を指定する言語構文の事をいいます。XPathはXMLとは別の構文を使用します。XMLドキュメントの抽象、論理ストラクチャ上で動作します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Scrapy

Scrapyは、Pythonで開発されたオープンソースソフトウェアです。スクレイピングという、Webサービスから必要な情報を取り出したり自動操作をしたりする技術を使うものです。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2018/11/05 02:30

編集2018/11/15 09:37

###■経緯
とあるtableから、3列目のimg数が不規則なtdからsrc属性の値を抽出して、そのテーブル構造(行,列)を保ちながらcsvファイルとして出力を試みています。

その際、複数のimgがtd内にある場合、下のScrapyコードでは、HTML上「◯」のimg srcは抽出できるのですが、「★」の値が抽出できません。

###■質問
HTML上の「◯」「★」両方の値を、テーブル構造(行,列)を保ちながらcsvとして出力できるScrapyコード(XPathの指定方法)を教えていただけますでしょうか。

なんとなくですが、extract_first()の部分をうまく修正すれば2つ目のimg srcの値「★」も抽出できるのではないかと想像しています。

HTML

1<table> 2 <tbody> 3 <tr> 4 <td>A3</td> 5 <td>B3</td> 6 <td> 7 <img src="../../media/test1.gif"> <!-- ◯ --> 8 <img src="../../media/test2.gif"> <!-- ★ --> 9 </td> 10 </tr> 11 <tr> 12 <td>A2</td> 13 <td>B2</td> 14 <td> 15 <img src="../../media/test3.gif"> 16 </td> 17 </tr> 18 </tbody> 19</table>

PythonScrapy

1table_rows = response.xpath('//table/tbody/tr') 2 3for table_row in table_rows: 4 item = TutorialItem() 5 item['time'] = table_row.xpath('td[1]/text()').extract_first() 6 item['note'] = table_row.xpath('td[3]/img/@src').extract_first() 7 yield item

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

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

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

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

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

seastar3

2018/11/05 10:23

XMLの原理とプログラム上での操作の理解が必要な処理ですから、がタブとしては、XPathの前提であるXMLが入るでしょう。PythonでのXML操作入門のサイトをググってみましょう。
guest

回答4

0

ベストアンサー

scrapyを入れて試してみました
test1.gifとtest2.gifを取得できてますし、test3.gifは違うリストになっているはずですが

CSV出力結果をだしてもらえますか?

https://doc.scrapy.org/en/latest/topics/exporters.html#csvitemexporter
リストの場合カンマで結合されていると思うのですが違うのでしょうか?

sh

1scrapy shell ./test.html
for i in response.xpath('//table/tbody/tr'): print(i.xpath('td[1]/text()').extract_first()) print(i.xpath('td[3]/img/@src').extract()) print('-' * 20)
A3 ['../../media/test1.gif', '../../media/test2.gif'] -------------------- A2 ['../../media/test3.gif'] --------------------

投稿2018/11/15 13:24

barobaro

総合スコア1286

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

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

fukazume

2018/11/16 01:40

おっしゃる通り、extract()に変更することで期待した通りのリストに格納できていました!shellで試しているうちに見誤ったのかもしれません。お騒がせいたしましたが、得るものもありました。精巧なご指摘ありがとうございました!
guest

0

scrapyはあまり試したことないのでわかりませんが

サンプルで取得できているのでしたら.extract_first()を.extract()に変更するだけでいいのでは?

.extract_first()は一番最初のデータしか取得できませんので複数取得する場合は.extract()になります。

python

1table_rows = response.xpath('//table/tbody/tr') 2 3for table_row in table_rows: 4 item = TutorialItem() 5 item['time'] = table_row.xpath('td[1]/text()').extract_first() 6 item['note'] = table_row.xpath('td[3]/img/@src').extract() 7 yield item

BeautifulSoupでしたら

python

1from bs4 import BeautifulSoup 2 3html = """ 4<table> 5 <tbody> 6 <tr> 7 <td>A3</td> 8 <td>B3</td> 9 <td> 10 <img src="../../media/test1.gif"> <!-- ◯ --> 11 <img src="../../media/test2.gif"> <!-- ★ --> 12 </td> 13 </tr> 14 <tr> 15 <td>A2</td> 16 <td>B2</td> 17 <td> 18 <img src="../../media/test3.gif"> 19 </td> 20 </tr> 21 </tbody> 22</table> 23""" 24 25soup = BeautifulSoup(html, 'html.parser') 26 27for trs in soup.select('tr'): 28 29 result = [] 30 31 for tds in trs.select('td'): 32 if tds.img: 33 for i in tds.select('img'): 34 result.append(i.get('src')) 35 else: 36 result.append(tds.get_text(strip=True)) 37 38 print(result)

結果
['A3', 'B3', '../../media/test1.gif', '../../media/test2.gif']
['A2', 'B2', '../../media/test3.gif']

投稿2018/11/15 08:53

編集2018/11/15 11:58
barobaro

総合スコア1286

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

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

fukazume

2018/11/15 09:46

ご回答ありがとうございます。extract()ですと、上記サンプルコードを例に取りますと、test1.gif, test2.gif, test3.gif の全てを抽出してしまうんです。。 私は、test1.gifとtest2.gifのimg srcを取得して、対応するフィールド内に格納したい(=テーブル構造(行,列)を保ちながらcsvファイルとして出力を試みている)のですが、難しいでしょうか? 表題の通り、imgだけに留まらず、pなどtd内に複数要素を記述しているソースに対して、有効な回避策も思いつかず困っている状況です。
barobaro

2018/11/15 12:01

タグ内にimgが二つ以上ある場合はどのような結果にしたいのでしょうか BeautifulSoupでサンプルと出力結果を書きました。
fukazume

2018/11/16 01:42

こちらのアプローチも参考になりました。ありがとうございます!
guest

0

pythonでXMLの操作として、次のコードは通りますか。試してみて下さい。

python

1items = response.xpath('//table/tbody/tr/td/img/@src") 2for item in items: 3 yield item

投稿2018/11/05 10:18

seastar3

総合スコア2285

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

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

fukazume

2018/11/05 10:33 編集

引き続き、ありがとうございます! @src") → @src') に編集して以下のエラーがズラッと返ってきます。何かヒントになりますでしょうか。 [scrapy.core.scraper] ERROR: Spider must return Request, BaseItem, dict or None, got 'Selector' in 〜
seastar3

2018/11/05 11:56

5行目のコード間違えて申し訳ありません。訂正します。
guest

0

検証していないのですが、考え方はXMLのやり方でtrタグごとの集合を取り、このtrタグ内のtd/imgの集合を取り、そのsrc属性を配列itmesとして抜き出し、これもitemの要素に分けて戻します。xpathのレベルに対応したforの入れ子のコードになります。

python

1table_rows = response.xpath('//table/tbody/tr') 2 3for table_row in table_rows: 4 nodes = table_row.xpath('td/img') 5 6 for node in nodes: 7 items = node.xpath('@src') 8 9 for item in items: 10 yield item

投稿2018/11/05 08:51

編集2018/11/05 11:57
seastar3

総合スコア2285

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

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

seastar3

2018/11/05 09:13

シンプルに"item = response.xpath('//table/tbody/tr/td/img/@src"でも、配列はとれますが、ご要望のrowごとの編集が入るでしょうから、2重のループにしてみたわけです。
fukazume

2018/11/05 09:49

ご回答ありがとうございます。やはり、 ・1つ目のimg src属性の値は、抽出できた ・2つ目のimg src属性の値は、抽出できなかった という同じ結果でした。 妥協案と言うか、以下のようにimg[2]とXPath指定してあげれば、2つ目のimg srcがある場合に抽出できるのですが。 item['note'] = table_row.xpath('td[3]/img[2]/@src').extract_first()
seastar3

2018/11/05 10:11

src要素もリストですね。もう一度しらみつぶしループにかけてみましょう。
fukazume

2018/11/05 10:45

お付き合いいただきありがとうございます。以下のように頂いたソースをインデントエラーが出るため編集し実行しましたが、やはり以下のエラーが発生しますね。難しいです(^_^;) [scrapy.core.scraper] ERROR: Spider must return Request, BaseItem, dict or None, got 'Selector' in 〜 ---------------------------- table_rows = response.xpath('//table/tbody/tr') for table_row in table_rows: nodes = table_row.xpath('td/img') for node in nodes: items = node.xpath('@src') <エラーが出るのでインデントしました> for item in items: yield item
seastar3

2018/11/05 11:58

5行目のコード間違えて申し訳ありません。訂正します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問