วิธีใช้ grep และ cut in script เพื่อรับ URL เว็บไซต์จากไฟล์ HTML


21

ฉันกำลังพยายามใช้ grep และตัดเพื่อแยก URL จากไฟล์ HTML ลิงค์มีลักษณะดังนี้:

<a href="http://examplewebsite.com/">

เว็บไซต์อื่น ๆ ที่มี.net, แต่ฉันคิดว่าฉันจะให้ตัดออกจากจุดที่เหมาะสมก่อน.gov >ดังนั้นฉันรู้ว่าฉันสามารถใช้ grep และตัดเพื่อตัดทุกอย่างก่อน http และหลัง. com แต่ฉันติดอยู่ในขณะนี้


ฉันแก้ไขมัน สำหรับบางคนไม่สนใจช่องว่างระหว่าง <และ a, HTML จะไม่ปรากฏขึ้นหากไม่มี ขอบคุณสำหรับการจับ!
eltigre

ใช้การจัดรูปแบบรหัส (เลือกข้อความและกด Ctrl-K) มิฉะนั้น<>บังคับให้มันถูกมองว่าเป็นแท็ก HTML
muru

ทำไมไม่ตรงกับการเปิดและการสิ้นสุดของพารามิเตอร์ href นอกจากนี้ฉันเชื่อว่านิพจน์ทั่วไปไม่เหมาะกับ html
把友情留在无盐

ฉันต้องการเขียนคำสั่งโดยใช้ grep เฉพาะและตัดเพื่อทำ ฉันรู้ว่ามีวิธีอื่น ๆ แต่ฉันอยากรู้เกี่ยวกับสิ่งเหล่านั้น
eltigre

9
โดยทั่วไปไม่ควรแยก HTML ด้วยนิพจน์ทั่วไปเนื่องจาก HTML ไม่ใช่ภาษาปกติ หากคุณสามารถรับประกันได้ว่า HTML ที่คุณแยกกำลังค่อนข้างง่ายและสิ่งที่คุณกำลังพยายามที่จะคาดเดาได้สารสกัดที่คุณอาจจะสามารถที่จะได้รับไปด้วย แต่โปรดดูstackoverflow.com/a/1732454/4014959
PM 2Ring

คำตอบ:


25

ตามที่ฉันได้กล่าวไว้ในความคิดเห็นของฉันโดยทั่วไปไม่ควรแยก HTML ด้วยนิพจน์ทั่วไป แต่บางครั้งคุณก็สามารถหลีกเลี่ยงได้หาก HTML ที่คุณกำลังแยกวิเคราะห์นั้นมีความประพฤติดี

เพื่อให้ได้เฉพาะ URL ที่อยู่ในhrefคุณสมบัติของ<a>องค์ประกอบฉันพบว่ามันง่ายที่สุดในการทำหลายขั้นตอน จากความคิดเห็นของคุณดูเหมือนว่าคุณต้องการโดเมนระดับบนสุดเท่านั้นไม่ใช่ URL แบบเต็ม ในกรณีนี้คุณสามารถใช้สิ่งนี้:

grep -Eoi '<a [^>]+>' source.html |
grep -Eo 'href="[^\"]+"' | 
grep -Eo '(http|https)://[^/"]+'

โดยที่source.htmlเป็นไฟล์ที่มีรหัส HTML ที่จะแยกวิเคราะห์

รหัสนี้จะพิมพ์ URL ระดับบนสุดทั้งหมดที่เกิดขึ้นเป็นhrefแอตทริบิวต์ของ<a>องค์ประกอบใด ๆในแต่ละบรรทัด -iตัวเลือกที่จะเป็นครั้งแรกที่grepคำสั่งเพื่อให้แน่ใจว่ามันจะทำงานได้ทั้งบน<a>และ<A>องค์ประกอบ ฉันเดาว่าคุณสามารถให้-iอันดับที่ 2 grepในการจับHREFคุณสมบัติตัวพิมพ์ใหญ่ OTOH ฉันต้องการละเว้น HTML ที่เสียหายเช่นนั้น :)

เพื่อประมวลผลเนื้อหาของ http://google.com/

wget -qO- http://google.com/ |
grep -Eoi '<a [^>]+>' | 
grep -Eo 'href="[^\"]+"' | 
grep -Eo '(http|https)://[^/"]+'

เอาท์พุต

http://www.google.com.au
http://maps.google.com.au
https://play.google.com
http://www.youtube.com
http://news.google.com.au
https://mail.google.com
https://drive.google.com
http://www.google.com.au
http://www.google.com.au
https://accounts.google.com
http://www.google.com.au
https://www.google.com
https://plus.google.com
http://www.google.com.au

ผลลัพธ์ของฉันแตกต่างจากตัวอย่างเล็กน้อยเล็กน้อยเมื่อฉันถูกเปลี่ยนเส้นทางไปยังหน้า Google ของออสเตรเลีย


ขอขอบคุณ. ตอนนี้เป็นสิ่งที่ฉันกำลังมองหา นี่เป็นวิธีที่สะอาดที่สุดในการทำ
eltigre

@eltigre: ความสุขของฉัน! แต่โปรดฟังคำเตือนที่ฉันเชื่อมโยงในความคิดเห็นของฉันด้านบน :)
PM 2Ring

ฉันมาถึงคำถามนี้โดยคาดหวังจุดง่าย ๆ ... และคุณก็ตะปูบนหัวเรียบร้อยแล้ว
Mark K Cowan

ขอบคุณ @ MarkKCowan :) FWIW ฉันเริ่มเขียนคำตอบโดยใช้ awk แต่ฉันตัดสินใจว่า grep-based solution จะเข้าใจง่ายขึ้นสำหรับผู้ที่ไม่คุ้นเคยกับ awk และรหัสข้างบนนั้นสั้นกว่ารหัส awk ของฉัน
PM 2Ring

2
@mavavilj: เพราะ OP เพียงต้องการโดเมนระดับบนสุดดังนั้นหลังจากที่://เราจะยอมรับตัวอักษรก่อนคนแรกหรือ/ "แต่ถ้าคุณต้องการดู URL แบบเต็มให้เปลี่ยนคำสั่งgrep -Eo '(http|https)://[^"]+นั้นเป็น ตัวเลือกอื่นสำหรับบรรทัดนั้นคือgrep -Eo '(http|https)://[^?"]+'การตัดตัวเลือกแบบสอบถาม อย่างไรก็ตามรูปแบบนั้นจะยังคงพิมพ์ URL ที่อยู่ใน URL อื่นเป็นพารามิเตอร์การสืบค้น แต่จะมีการพิมพ์ในบรรทัดแยกต่างหาก
PM

25

ไม่แน่ใจว่าคุณ จำกัด เครื่องมือหรือไม่:

แต่ regex อาจไม่ใช่วิธีที่ดีที่สุดที่จะไปตามที่กล่าวไว้ แต่นี่เป็นตัวอย่างที่ฉันได้รวบรวม:

cat urls.html | grep -Eo "(http|https)://[a-zA-Z0-9./?=_-]*" | sort -u
  • grep -E: เหมือนกับ egrep
  • grep -o: แสดงเฉพาะสิ่งที่ได้รับ grepping
  • (http | https): คือ / หรือ
  • az: เป็นตัวพิมพ์เล็กทั้งหมด
  • อาริโซน่า: เป็นกรณีที่ uper ทั้งหมด
  • . : คือจุด
  • \?: คือ ?
  • *: ทำซ้ำกลุ่ม [... ]
  • uniq: จะลบรายการที่ซ้ำกัน

เอาท์พุท:

bob@bob-NE722:~s$  wget -qO- https://stackoverflow.com/ | grep -Eo "(http|https)://[a-zA-Z0-9./?=_-]*" | sort -u
https://stackauth.com
https://meta.stackoverflow.com
https://cdn.sstatic.net/Img/svg-icons
https://stackoverflow.com
https://www.stackoverflowbusiness.com/talent
https://www.stackoverflowbusiness.com/advertising
https://stackoverflow.com/users/login?ssrc=head
https://stackoverflow.com/users/signup?ssrc=head
https://stackoverflow.com
https://stackoverflow.com/help
https://chat.stackoverflow.com
https://meta.stackoverflow.com
...

นอกจากนี้คุณยังสามารถเพิ่ม\dเข้าไปในประเภทตัวเลขอื่น ๆ


2
IRI regexes! ใช้หนึ่งในนั้นและทำให้ตกใจ OP! :)
muru

2
@muru ... ตัวสั่นฉัน ... ฉันไม่รู้จะพูดยังไงดี เป็นของจริงเหรอ!
jmunsch

4
@jmunsch, uniq เพียงลบรายการที่อยู่ติดกัน sort -u?
JJoao

1
มันใช้งานได้ดีคำตอบที่ดีที่สุด !!
Gery

@JJoao เป็นแหล่งสำหรับ sort -u เร็วกว่า piping หรือไม่ เพียงแค่การทดสอบความคิด id ต้องดู แต่คุณอาจพูดถูกเกี่ยวกับ shell middleware
jmunsch

9

หาก grep ของคุณรองรับ Perl regexes:

grep -Po '(?<=href=")[^"]*(?=")'
  • (?<=href=")และ(?=")มีLookAroundการแสดงออกสำหรับhrefแอตทริบิวต์ สิ่งนี้ต้องการ-Pตัวเลือก
  • -o พิมพ์ข้อความที่ตรงกัน

ตัวอย่างเช่น:

$ curl -sL https://www.google.com | grep -Po '(?<=href=")[^"]*(?=")'
/search?
https://www.google.co.in/imghp?hl=en&tab=wi
https://maps.google.co.in/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
https://www.youtube.com/?gl=IN&tab=w1
https://news.google.co.in/nwshp?hl=en&tab=wn
...

ตามปกติไม่มีการรับประกันว่าสิ่งเหล่านี้เป็น URIs ที่ถูกต้องหรือ HTML ที่คุณกำลังวิเคราะห์คำจะถูกต้อง


8

ในฐานะทางเลือกอื่นที่ไม่ใช่ regexให้ใช้ลูกสุนัข :

pup 'a[href] attr{href}' < yourfile.html

จะค้นหาaองค์ประกอบทั้งหมดที่มีhrefแอตทริบิวต์จากนั้นแสดงค่าของhrefแอตทริบิวต์

ในการติดตั้งpupคุณต้องใช้ (ภาษาการเขียนโปรแกรม):

sudo apt-get install golang
sudo go get github.com/ericchiang/pup

ข้อดีของวิธีนี้ก็คือว่ามันไม่พึ่งพา HTML ที่มีการจัดรูปแบบ


1
+1 pupถึงเวลาสำหรับการติดตั้ง ....
ทำเครื่องหมาย K Cowan

คุณสามารถใส่ไว้ในไฟล์ได้เช่นกัน pup 'a.classname[href] attr{href}' < tut.html >links.md
Ahmad Awais

1

ฉันได้พบวิธีแก้ปัญหาที่นี่ที่ IMHO ง่ายกว่าและอาจเร็วกว่าที่เสนอไว้ที่นี่มาก ฉันได้ปรับเล็กน้อยเพื่อรองรับไฟล์ https แต่รุ่น TD; TR คือ ...

PS: คุณสามารถแทนที่ URL ของไซต์ด้วยพา ธ ไปยังไฟล์และมันจะทำงานในลักษณะเดียวกัน

lynx -dump -listonly -nonumbers "http://www.goggle.com" > links.txt

lynx -dump -listonly -nonumbers "some-file.html" > links.txt

หากคุณต้องการเห็นลิงก์แทนที่จะวางไว้ในไฟล์ลองใช้แทน ...

lynx -dump -listonly -nonumbers "http://www.google.com"

lynx -dump -listonly -nonumbers "some-file.html"

ผลลัพธ์จะมีลักษณะคล้ายกับต่อไปนี้ ...

http://www.google.ca/imghp?hl=en&tab=wi
http://maps.google.ca/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
http://www.youtube.com/?gl=CA&tab=w1
http://news.google.ca/nwshp?hl=en&tab=wn
https://mail.google.com/mail/?tab=wm
https://drive.google.com/?tab=wo
https://www.google.ca/intl/en/options/
http://www.google.ca/history/optout?hl=en
...
etc.

สำหรับกรณีการใช้งานของฉันมันใช้งานได้ดี แต่ระวังความจริงที่ว่าทุกวันนี้ผู้คนเพิ่มลิงค์เช่น src = "// blah.tld" สำหรับ CDN URI ของไลบรารี ฉันไม่ต้องการเห็นสิ่งเหล่านั้นในลิงค์ที่ดึงมา

ไม่จำเป็นต้องลองตรวจสอบลิงก์ href หรือแหล่งอื่น ๆ เพราะ "lynx -dump" จะแยกลิงก์ที่คลิกได้ทั้งหมดจากหน้าเว็บที่กำหนด ดังนั้นเพียงคิดว่าคุณต้องทำหลังจากนั้นคือการแยกผลลัพธ์ของ "lynx -dump" โดยใช้ grep เพื่อรับเวอร์ชันดิบที่สะอาดกว่าของผลลัพธ์เดียวกัน


แต่คำถามบอกว่า“ ดึง URL จากไฟล์ HTML [ที่ดูเหมือน]” (ตัวอย่าง) ไม่ใช่ “ ดึง URL ออกจากหน้าเว็บ” หากคำตอบของคุณสามารถใช้กับไฟล์ที่อยู่ในเครื่องท้องถิ่นให้อธิบายวิธีการ กรุณาอย่าตอบในความคิดเห็น; แก้ไขคำตอบของคุณเพื่อให้ชัดเจนและสมบูรณ์ยิ่งขึ้น
G-Man กล่าวว่า 'Reinstate Monica'

1
คุณสามารถแทนที่ URL ด้วยชื่อไฟล์
asiby

@ G-Man ทำไม -1 คุณต้องลองใช้รหัสด้วยตัวเองและดูว่ามันใช้ได้กับไฟล์ในตัวเครื่องด้วยเช่นกัน ฉันได้เพิ่มการชี้แจงว่าในกรณีที่มันไม่ชัดเจน
asiby

มันมีประโยชน์จริงๆ .. ถ้าคุณใช้กับ xargs มันก็คุ้มที่จะเพิ่ม | จัดเรียง | uniq เพื่อตัดลิงก์ที่ซ้ำกัน
Stuart Axon

0
wget -qO- google.com |
tr \" \\n | grep https\*://

... อาจจะทำได้ค่อนข้างดี ตามที่เขียนไว้มันพิมพ์:

http://schema.org/WebPage
http://www.google.com/imghp?hl=en&tab=wi
http://maps.google.com/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
http://www.youtube.com/?tab=w1
http://news.google.com/nwshp?hl=en&tab=wn
https://mail.google.com/mail/?tab=wm
https://drive.google.com/?tab=wo
http://www.google.com/intl/en/options/
http://www.google.com/history/optout?hl=en
https://accounts.google.com/ServiceLogin?hl=en&continue=http://www.google.com/
https://www.google.com/culturalinstitute/project/the-holocaust?utm_source=google&amp;utm_medium=hppromo&amp;utm_campaign=auschwitz_q1&amp;utm_content=desktop
https://plus.google.com/116899029375914044550

หากเป็นสิ่งสำคัญที่คุณต้องจับคู่ลิงก์และจากโดเมนระดับบนสุดเท่านั้นคุณสามารถทำได้:

wget -qO- google.com |
sed '/\n/P;//!s|<a[^>]*\(https*://[^/"]*\)|\n\1\n|;D'

... หรือสิ่งที่ชอบ - แต่สำหรับบางคนsedที่คุณอาจจำเป็นต้องใช้แทนตัวอักษร\nตัวอักษร ewline สำหรับแต่ละของทั้งสองที่ผ่านมาnของ

ดังที่เขียนไว้คำสั่งข้างต้นจะพิมพ์:

http://www.google.com
http://maps.google.com
https://play.google.com
http://www.youtube.com
http://news.google.com
https://mail.google.com
https://drive.google.com
http://www.google.com
http://www.google.com
http://www.google.com
https://www.google.com
https://plus.google.com

... และสำหรับกรณีใดกรณีหนึ่ง(แต่อาจเป็นประโยชน์มากที่สุดกับตัวหลัง)คุณสามารถตรึงบน|sort -uตัวกรองจนจบเพื่อรับรายการsorted และวางรายการที่ซ้ำกัน



-1
echo "<a href="http://examplewebsite.com/">"|sed -r 's:<.*"::g'|sed 's:/">$::g'

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