Pengamatan yang menarik! Saya menghabiskan beberapa jam terakhir untuk menyelidiki hal ini dan ternyata, ada lebih dari yang terlihat.
Jika Anda berasal dari CSS, Anda mungkin berharap untuk menulis a::text
dengan cara yang sama seperti Anda menulis a::first-line
, a::first-letter
, a::before
atau a::after
. Tidak ada kejutan di sana.
Di sisi lain, sintaksis pemilih standar akan menyarankan bahwa a ::text
cocok dengan elemen semu ::text
dari keturunan elemen a
, sehingga setara dengan a *::text
. Namun, .product-list-product-wrapper .product-name a
tidak memiliki elemen turunan apa pun, jadi, a ::text
seharusnya tidak cocok dengan apa pun. Fakta bahwa itu cocok menunjukkan bahwa Scrapy tidak mengikuti tata bahasanya.
Scrapy menggunakan Parsel (berbasis cssselect) untuk menerjemahkan penyeleksi ke XPath, dari situlah ::text
berasal. Dengan mengingat hal tersebut, mari kita periksa bagaimana Parsel mengimplementasikan ::text
:
>>> from parsel import css2xpath
>>> css2xpath('a::text')
'descendant-or-self::a/text()'
>>> css2xpath('a ::text')
'descendant-or-self::a/descendant-or-self::text()'
Jadi, seperti cssselect, apa pun yang mengikuti kombinator turunan diterjemahkan ke dalam sumbu descendant-or-self
, tetapi karena node teks adalah turunan yang tepat dari node elemen di DOM, ::text
diperlakukan sebagai node mandiri dan dikonversi langsung ke text()
, yang mana, dengan descendant-or-self
sumbu, cocok dengan simpul teks mana pun yang merupakan turunan dari elemen a
, sama seperti a/text()
cocok dengan simpul teks mana pun anak dari elemen a
(anak juga merupakan turunan).
Yang mengerikan, ini terjadi bahkan ketika Anda menambahkan *
eksplisit ke pemilih:
>>> css2xpath('a *::text')
'descendant-or-self::a/descendant-or-self::text()'
Namun, penggunaan sumbu descendant-or-self
berarti a ::text
dapat mencocokkan semua node teks dalam elemen a
, termasuk yang ada di elemen lain yang bersarang di dalam a
. Dalam contoh berikut, a ::text
akan mencocokkan dua node teks: 'Link '
diikuti oleh 'text'
:
<a href="https://example.com">Link <span>text</span></a>
Jadi, meskipun penerapan ::text
oleh Scrapy merupakan pelanggaran berat terhadap tata bahasa Selectors, tampaknya hal ini dilakukan dengan sengaja.
Faktanya, elemen semu Scrapy lainnya ::attr()
1 berperilaku serupa. Selector berikut semuanya cocok dengan node atribut id
milik elemen div
ketika tidak memiliki elemen turunan apa pun:
>>> css2xpath('div::attr(id)')
'descendant-or-self::div/@id'
>>> css2xpath('div ::attr(id)')
'descendant-or-self::div/descendant-or-self::*/@id'
>>> css2xpath('div *::attr(id)')
'descendant-or-self::div/descendant-or-self::*/@id'
... tetapi div ::attr(id)
dan div *::attr(id)
akan cocok dengan semua node atribut id
dalam turunan div
bersama dengan atribut id
miliknya sendiri, seperti pada contoh berikut:
<div id="parent"><p id="child"></p></div>
Tentu saja, ini adalah kasus penggunaan yang kurang masuk akal, jadi kita harus bertanya-tanya apakah ini merupakan efek samping yang tidak disengaja dari penerapan ::text
.
Bandingkan penyeleksi elemen semu dengan penyeleksi elemen semu yang menggantikan selektor sederhana apa pun:
>>> css2xpath('a [href]')
'descendant-or-self::a/descendant-or-self::*/*[@href]'
Ini dengan benar menerjemahkan kombinator turunan ke descendant-or-self::*/*
dengan sumbu child
implisit tambahan, memastikan bahwa predikat [@href]
tidak pernah diuji pada elemen a
.
Jika Anda baru mengenal XPath, Selectors, atau bahkan Scrapy, ini semua mungkin tampak membingungkan dan membebani. Jadi, inilah ringkasan kapan harus menggunakan satu pemilih dibandingkan pemilih lainnya:
Gunakan a::text
jika elemen a
Anda hanya berisi teks, atau jika Anda hanya tertarik pada node teks tingkat atas dari elemen a
ini dan bukan elemen bertumpuknya.
Gunakan a ::text
jika elemen a
Anda berisi elemen bersarang dan Anda ingin mengekstrak semua node teks dalam elemen a
ini.
Meskipun Anda dapat menggunakan a ::text
jika elemen a
Anda hanya berisi teks, sintaksisnya membingungkan, jadi demi konsistensi, gunakan a::text
sebagai gantinya.
1 Yang menarik, ::attr()
muncul di (ditinggalkan mulai tahun 2021) Spesifikasi Selectors Non-elemen, yang seperti yang Anda harapkan berperilaku konsisten dengan tata bahasa Selectors, sehingga perilakunya di Scrapy tidak konsisten dengan spesifikasi. ::text
di sisi lain jelas-jelas hilang dari spesifikasi; berdasarkan jawaban ini, saya rasa Anda dapat menebak alasannya secara masuk akal.
person
BoltClock
schedule
01.02.2018
::text
elemen semu? Saya tidak dapat menemukan apa pun tentang keberadaannya... - person Andersson   schedule 01.02.2018::text
, baik itu perpustakaanBeautifulSoup
ataulxml
. Namun, jika ingin mengurainya menggunakan scrapy maka ini wajib::text
untuk mendapatkan teksnya. Anda tahu betul hal itu. Intinya adalah: Saya tidak menemukan banyak perbedaan menggunakan spasi di antaranya untuk mengurai teks apa pun dari beberapa elemen tetapi harus adado's and don'ts
tentang penggunaannya. Itulah yang ingin saya ketahui. - person SIM   schedule 01.02.2018::text
:) Saya hanya belum pernah mendengar tentang elemen semu ini. IMHO Saya tidak berpikir bahwa ruang dapat membuat perbedaan apa pun dalam kasus Anda... Saya juga tidak berpikir bahwa pertanyaan ini pantas mendapat suara negatif :) - person Andersson   schedule 01.02.2018