ข้อความระหว่างสองแท็ก


23

ฉันต้องการดึงสิ่งที่อยู่ระหว่างแท็กสองแท็กเหล่านี้<tr> </tr>- จากเอกสาร html ตอนนี้ฉันไม่มีข้อกำหนด html เฉพาะใด ๆ ที่จะรับประกันการแยกวิเคราะห์ html ฉันเพียงแค่ต้องการสิ่งธรรมดาที่การแข่งขัน<tr>และ</tr>และได้รับทุกอย่างในระหว่างและอาจจะมีหลายtrs ฉันลอง awk ซึ่งใช้งานได้ แต่ด้วยเหตุผลบางอย่างมันทำให้ฉันซ้ำซ้อนของแต่ละแถวที่แยกออกมา

awk '
/<TR/{p=1; s=$0}
p && /<\/TR>/{print $0 FS s; s=""; p=0}
p' htmlfile> newfile

จะไปเกี่ยวกับเรื่องนี้ได้อย่างไร


IIUC สคริปต์ awk '/<tr/{p=1}; p; /<\/tr>/{p=0}'ของคุณควรจะเป็น: โพสต์ตัวอย่างอินพุตและเอาต์พุตที่คาดหวังหากไม่ได้ผล
Thor

ตั้งแต่ของคุณawkคือการทำงาน แต่ให้ซ้ำกันพยายามที่จะผ่านผลผลิต awk ของคุณจากsort -uการได้รับพวกเขาที่แตกต่างกัน
igiannak

คำตอบ:


14

หากคุณต้องการ...ทั้งหมด<tr>...</tr>ทำ:

grep -o '<tr>.*</tr>' HTMLFILE | sed 's/\(<tr>\|<\/tr>\)//g' > NEWFILE

สำหรับ multiline ทำ:

tr "\n" "|" < HTMLFILE | grep -o '<tr>.*</tr>' | sed 's/\(<tr>\|<\/tr>\)//g;s/|/\n/g' > NEWFILE

ตรวจสอบ HTMLFILE ก่อนถ่าน "|" (ไม่ใช่ปกติ แต่เป็นไปได้) และหากมีอยู่ให้เปลี่ยนเป็นอันที่ไม่มีอยู่


1
ซึ่งจะใช้งานได้หากแท็กเริ่มต้นและแท็กสิ้นสุดอยู่ในบรรทัดเดียวกัน
l0b0

echo "bla<tr>foo</tr>bla<tr>bar</tr>bla" | grep -o '<tr>.*</tr>' | sed 's/\(<tr>\|<\/tr>\)//g'fooblabarจะช่วยให้ blaไม่ควรจะมี?
NN

@ l0b0 ถูกต้อง จะเข้ากันได้กับ multiline ...
xx4h

grep -Po '<tr>.*?</tr>'จะส่งคืนผลลัพธ์หนึ่งรายการต่อบรรทัดในกรณีของ @ NN แต่ไม่สามารถพกพาได้
l0b0

ฉันไม่แน่ใจว่าคุณหมายถึง 'specs' หรือ 'spec-style' แต่โปรดทราบว่าเว็บเบราว์เซอร์ของคุณใช้ตัวแยกวิเคราะห์ htmlและตัวแยกวิเคราะห์ html จะแยกวิเคราะห์ HTML โดยไม่คำนึงถึงวิธีการเขียน มันจะไม่แยกวิเคราะห์สิ่งที่ไม่ใช่ html แต่จะไม่มีเบราว์เซอร์ของคุณดังนั้นจะไม่มีใครรบกวนการเขียน "html" ที่ parser แยกวิเคราะห์ไม่ได้ กล่าวอีกนัยหนึ่ง: ตัวแยกวิเคราะห์ที่ดีแน่นอนทางออกที่ดีที่สุดของคุณสำหรับการทำเช่นนี้
goldilocks

11

คุณมีข้อกำหนดที่รับประกันตัวแยกวิเคราะห์ HTML: คุณต้องแยกวิเคราะห์ HTML Perl's HTML :: TreeBuilder , Python BeautifulSoupและอื่น ๆ ใช้งานง่ายกว่าการเขียนนิพจน์ทั่วไปที่ซับซ้อนและเปราะง่าย

perl -MHTML::TreeBuilder -le '
    $html = HTML::TreeBuilder->new_from_file($ARGV[0]) or die $!;
    foreach ($html->look_down(_tag => "tr")) {
        print map {$_->as_HTML()} $_->content_list();
    }
' input.html

หรือ

python -c 'if True:
    import sys, BeautifulSoup
    html = BeautifulSoup.BeautifulSoup(open(sys.argv[1]).read())
    for tr in html.findAll("tr"):
        print "".join(tr.contents)
' input.html

9

sedและawkไม่เหมาะสำหรับงานนี้คุณควรใช้เครื่องมือแยกวิเคราะห์ html ที่เหมาะสม ตัวอย่างhxselectจาก w3.org:

<htmlfile hxselect -s '\n' -c 'tr'

ฉันไม่รู้ว่า hxselect เป็นตัวเลือกที่ดีที่สุดหรือไม่ ฉันไม่ได้ใช้แต่หน้าคนบอกว่า "อ่านเอกสาร XML ที่มีรูปแบบถูกต้อง" ซึ่งเอกสาร html จำนวนมากไม่ใช่ อาจเป็นมูลค่าลอง tho ตัวแยกวิเคราะห์ html พร้อมใช้งานสำหรับ perl, python และอื่น ๆ อัล จะดีขึ้นมากถ้าเป็นตัวเลือก
goldilocks

2
@ goldilocks: ทางเลือกที่ดีที่สุดขึ้นอยู่กับสถานการณ์ จากประสบการณ์ของฉันทำงานได้hxselectค่อนข้างดีด้วยเอกสาร html / xml นอกจากนี้ยังใช้งานได้เร็วกว่า perl, python และอื่น ๆ ฉันคิดว่าhxselectเป็นสื่อกลางที่ดีระหว่างsed/ awkและ libs parser
Thor

1
ถ้ามันใช้งานได้ดีมาก! ฉันเพิ่งเพิ่มข้อแม้สำหรับ TechJack ในกรณีที่มันไม่ได้ - เนื่องจากฉันยังแนะนำให้ใช้ parser บางชนิด;) lib โปรแกรมการเขียนโปรแกรมเป็นเรื่องที่น่าอึดอัดใจมากขึ้น แต่ควรจัดการกับสิ่งที่อยู่ห่างไกลในรูปแบบ html
goldilocks

Thor hxselectดูดีจะมีการสำรวจต่อไปอย่างแน่นอน ขอบคุณ
TechJack

@goldilocks: hxnormalizeดูแลไฟล์ html / xml ที่มีรูปแบบไม่ดี
tokland

5

หากrubyพร้อมใช้งานคุณสามารถทำสิ่งต่อไปนี้

ruby -e 'puts readlines.join[/(?<=<tr>).+(?=<\/tr>)/m].gsub(/<\/?tr>/, "")' file

fileไฟล์ html อินพุตของคุณอยู่ที่ไหน คำสั่งดำเนินการ Ruby one-liner ก่อนอื่นมันจะอ่านทุกบรรทัดจากfileและรวมเข้าไปในสตริง, readlines.join. จากนั้นจากสตริงจะเลือกอะไรระหว่าง ( แต่ไม่รวม) <tr>และที่เป็นตัวละครตัวหนึ่งหรืออีกต่อไปโดยไม่คำนึงถึงบรรทัดใหม่<\/tr> [/(?<=<tr>).+(?=<\/tr>)/m]จากนั้นจะลบสตริงใด ๆ<tr>หรือ</tr>จากสตริงgsub(/<\/?tr>/, "")(จำเป็นต้องจัดการtrแท็กที่ซ้อนกัน) putsในที่สุดก็พิมพ์สตริง

คุณบอกว่าตัวแยกวิเคราะห์ html ไม่ได้รับประกันสำหรับคุณ แต่มันง่ายมากที่จะใช้Nokogiriด้วยrubyและทำให้คำสั่งนั้นง่ายขึ้น

ruby -rnokogiri -e 'puts Nokogiri::HTML(readlines.join).xpath("//tr").map { |e| e.content }' file

-rnokogiriโหลด Nokogiri อ่านทุกบรรทัดของNokogiri::HTML(readlines.join) หยิบออกทุกองค์ประกอบและหยิบออกเนื้อหาสำหรับแต่ละองค์ประกอบคือสิ่งที่อยู่ระหว่างและfilexpath("//tr")trmap { |e| e.content }<tr></tr>


1

grep

หากต้องการดึงเนื้อหาภายในtrแท็กข้ามหลายบรรทัดให้ส่งผ่านxargsก่อนตัวอย่างเช่น:

curl -sL https://www.iana.org/ | xargs | egrep -o "<tr>.*?</tr>"

ในการส่งคืน HTML ภายในเท่านั้นให้ใช้:

curl -sL https://www.iana.org/ | xargs | grep -Po "<tr>\K(.*?)</tr>" | sed "s/..tr.//g"

ตรวจสอบไวยากรณ์สำหรับperlreรูปแบบเพิ่มเติม

หมายเหตุ: เพื่อประสิทธิภาพที่รวดเร็วกว่าคุณอาจพิจารณาว่าripgrepมีไวยากรณ์ใดที่คล้ายกัน


มันพิมพ์ออกมาดูดีกว่าโดยไม่มี xargs มีประโยชน์ในการค้นหาจาวาสคริปต์แบบอินไลน์โดยใช้ egrep -o "<script. *? </script>"
Andrew

0

pup

ตัวอย่างการใช้pup(ซึ่งใช้ตัวเลือก CSS ):

pup -f myfile.html tr

pup -f myfile.html tr text{}หากต้องการพิมพ์ข้อความเท่านั้นโดยไม่ต้องแท็กใช้:

นี่คือตัวอย่างบางส่วนด้วยcurl:

curl -sL https://www.iana.org/ | pup tr text{}
pup -f <(curl -sL https://www.iana.org/) tr text{}

xpup

ตัวอย่างการใช้xpupการแยกวิเคราะห์ HTML / XML (ซึ่งรองรับ XPath):

xpup -f myfile.html "//tr"

0

หากเป็นเพียงรายชื่อสั้น ๆ ของ<tr>สิ่งนี้สามารถช่วย:

perl -ne 'print if /<tr>/../</tr>/' your.html > TRs.log

ไชโย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.