scrapyでxpath, cssを使って要素を抽出するときに、よく使うセレクタをチートシート的にまとめておく。
抽出の元となるHTMLはこんな感じとする。
<html>
<body>
<div id="main">
<ul>
<li data="1">list1</li>
<li data="2" class="even">list2</li>
<li data="3">list3</li>
</ul>
<div>aaa<div>bbb</div></div>
</div>
<div id="sub">
<ul>
<li data="1">list4</li>
<li data="2" class="even">list5</li>
<li data="3">list6</li>
</ul>
<div>ccc<div>ddd</div></div></div>
</body>
</html>
xpath, cssチートシート
xpath | css | 説明 |
---|---|---|
//li/text() |
li::text |
text要素 |
//div[@id="main"] |
div#main |
id指定フィルタ |
//li[@class="even"] |
li.even |
class指定フィルタ |
//li[@data="3"] |
li[data="3"] |
属性指定フィルタ |
//div[@id="main"]/div |
div#main>div |
直下の子取得 |
//li/@data |
li::attr(data) |
属性取得 |
text要素をextract
res.xpath('//li/text()').extract()
res.css('li::text').extract()
→ [‘list1’, ‘list2’, ‘list3’, ‘list4’, ‘list5’, ‘list6’]
最初の要素をextract
res.xpath('//li/text()').extract_first() # extract_first
res.xpath('//li/text()')[0].extract() # selectorの1要素目からextract
res.css('li::text').extract_first()
res.css('li::text')[0].extract()
→ ‘list1’
id指定でフィルタ
res.xpath('//div[@id="main"]//li/text()').extract() # [@id="main"]
res.css('div#main li::text').extract() # #main
→ [‘list1’, ‘list2’, ‘list3’]
class指定でフィルタ
res.xpath('//div[@id="main"]//li[@class="even"]/text()').extract() # [@class="even"]
res.css('div#main li.even::text').extract() # .even
→ [‘list2’]
属性指定でフィルタ
res.xpath('//div[@id="main"]//li[@data="3"]/text()').extract() # [@data="3"]
res.css('div#main li[data="3"]::text').extract() # [data="3"]
→ [‘list3’]
直下の子要素指定でフィルタ
res.xpath('//div[@id="main"]/div/text()').extract() # //divなら["aa", "bb"]になる
res.css('div#main>div::text').extract() # div#main divなら["aa", "bb"]になる
→ [‘aaa’]
属性取得
res.xpath('//li/@data').extract()
res.css('li::attr(data)').extract()
→ [‘1’, ‘2’, ‘3’, ‘1’, ‘2’, ‘3’]
Elementを取得してループ
# xpath
for elm in res.xpath("//li"):
#liの要素まで取得してからさらにそこからxpathで取得
data = elm.xpath('@data').get()
text = elm.xpath('text()').get()
print("{}\t{}".format(data, text))
#css
for elm in res.css("li"):
#liの要素まで取得してからさらにそこからcssで取得
data = elm.css('::attr(data)').get()
text = elm.css('::text').get()
print("{}\t{}".format(data, text))
→
1 list1
2 list2
3 list3
1 list4
2 list5
3 list6
全体的に、xpathのほうが冗長ですが理論的である気がしますね。xpathはhtmlだけではなくxmlに対して使える汎用的なものだからですね。
一方cssの方はjqueryやcssを書くことに慣れていれば、簡潔に(id指定やclass指定など)書けますが、選択ではなく取得になると「あれ?どうやるの?」って気になります。