Cách sử dụng grep và cắt theo tập lệnh để lấy URL trang web từ tệp HTML


21

Tôi đang cố gắng sử dụng grep và cắt để trích xuất URL từ tệp HTML. Các liên kết trông giống như:

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

Các trang web khác có .net, .govnhưng tôi cho rằng tôi có thể đưa ra điểm dừng ngay trước đó >. Vì vậy, tôi biết tôi có thể sử dụng grep và cắt bằng cách nào đó để cắt mọi thứ trước http và sau .com, nhưng tôi đã bị mắc kẹt trong một thời gian.


Tôi đã chỉnh sửa nó. Đối với một số người bỏ qua khoảng trắng giữa <và a, HTML sẽ không hiển thị nếu không có nó. Cảm ơn đã bắt nó!
eltigre

Sử dụng định dạng mã (chọn văn bản và nhấn Ctrl-K). Mặt khác, <>buộc nó phải được xem như là một thẻ HTML.
muru

Tại sao không khớp với trích dẫn mở đầu và kết thúc của tham số href? ngoài ra, tôi tin rằng các biểu thức thông thường không phù hợp nhất với html.
把 友情 留

Tôi muốn viết một lệnh bằng cách sử dụng grep cụ thể và cắt để làm điều đó. Tôi nhận ra có những cách khác, nhưng tôi muốn biết về những cách đó.
eltigre

9
Nói chung, không nên phân tích HTML bằng Biểu thức chính quy, vì HTML không phải là ngôn ngữ thông thường. Nếu bạn có thể đảm bảo rằng HTML mà bạn phân tích cú pháp khá đơn giản và những thứ bạn đang cố gắng trích xuất có thể dự đoán được thì bạn thể thoát khỏi nó. Nhưng vui lòng xem stackoverflow.com/a/1732454/4014959
PM 2Ring 27/1/2015

Câu trả lời:


25

Như tôi đã nói trong nhận xét của mình, nói chung không nên phân tích HTML bằng Biểu thức chính quy, nhưng đôi khi bạn có thể thoát khỏi nó nếu HTML mà bạn đang phân tích cú pháp hoạt động tốt.

Để chỉ nhận các URL hrefthuộc tính của <a>các thành phần, tôi thấy dễ dàng nhất để làm điều đó trong nhiều giai đoạn. Từ ý kiến ​​của bạn, có vẻ như bạn chỉ muốn tên miền cấp cao nhất chứ không phải URL đầy đủ. Trong trường hợp đó, bạn có thể sử dụng một cái gì đó như thế này:

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

nơi source.htmlchứa tệp HTML để phân tích cú pháp.

Mã này sẽ in tất cả các URL cấp cao nhất xuất hiện dưới dạng hrefthuộc tính của bất kỳ <a>thành phần nào trong mỗi dòng. Các -itùy chọn để là người đầu tiên greplệnh là để đảm bảo rằng nó sẽ làm việc trên cả hai <a><A>các yếu tố. Tôi đoán bạn cũng có thể cung cấp -icho người thứ 2 grepđể nắm bắt các HREFthuộc tính chữ hoa , OTOH, tôi muốn bỏ qua HTML bị hỏng như vậy. :)

Để xử lý nội dung của http://google.com/

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

đầu ra

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

Đầu ra của tôi hơi khác so với các ví dụ khác khi tôi được chuyển hướng đến trang Google của Úc.


CẢM ƠN BẠN. Bây giờ đây là chính xác những gì tôi đang tìm kiếm. Đây là cách sạch nhất để làm điều đó.
eltigre

@eltigre: Niềm vui của tôi! Nhưng xin hãy chú ý đến cảnh báo mà tôi đã liên kết trong bình luận của tôi ở trên. :)
PM 2Ring 27/1/2015

Tôi đã đến với câu hỏi này để mong đợi những điểm dễ dàng ... và bạn đã hoàn toàn đánh vào đầu mình
Mark K Cowan

Cảm ơn, @MarkKCowan. :) FWIW, ban đầu tôi bắt đầu viết câu trả lời bằng awk, nhưng sau đó tôi quyết định rằng một giải pháp dựa trên grep sẽ dễ hiểu hơn đối với những người không quen với awk. Và dù sao, mã ở trên ngắn hơn mã awk của tôi.
PM 2Ring

2
@mavavilj: Vì OP chỉ muốn tên miền cấp cao nhất, nên sau khi ://chúng tôi chỉ chấp nhận ký tự trước /hoặc đầu tiên ". Nhưng nếu bạn muốn xem URL đầy đủ, hãy thay đổi lệnh đó thành grep -Eo '(http|https)://[^"]+. Một tùy chọn khác cho dòng grep -Eo '(http|https)://[^?"]+'đó là cắt bỏ các tùy chọn truy vấn. Tuy nhiên, biến thể đó vẫn sẽ in các URL được chứa trong một URL khác dưới dạng tham số truy vấn, nhưng chúng sẽ được in trên một dòng riêng biệt.
PM 2Ring

25

Không chắc chắn nếu bạn bị giới hạn về các công cụ:

Nhưng regex có thể không phải là cách tốt nhất để đi như đã đề cập, nhưng đây là một ví dụ mà tôi kết hợp lại:

cat urls.html | grep -Eo "(http|https)://[a-zA-Z0-9./?=_-]*" | sort -u
  • grep -E: giống như egrep
  • grep -o: chỉ xuất ra những gì đã được grepping
  • (http | https): là một hoặc / hoặc
  • az: là tất cả chữ thường
  • AZ: là tất cả các trường hợp uper
  • . : là dấu chấm
  • \?: Là ?
  • *: đang lặp lại nhóm [...]
  • uniq: sẽ loại bỏ bất kỳ bản sao

Đầu ra:

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
...

Bạn cũng có thể thêm vào \dđể bắt các loại số khác.


2
IRI chế độ! Sử dụng một trong số họ và sợ OP! :)
muru

2
@muru ... tôi rùng mình ... tôi không biết phải nói gì. Chúng có thật không!?
jmunsch

4
@jmunsch, uniq chỉ cần loại bỏ các bản sao liền kề. sort -u?
JJoao

1
nó hoạt động tuyệt vời, câu trả lời tốt nhất !!
Gery

@JJoao là nguồn để sắp xếp -u nhanh hơn đường ống? Chỉ là một thử nghiệm suy nghĩ, id phải nhìn. Nhưng bạn có thể đúng, về phần mềm trung gian vỏ.
jmunsch

9

Nếu grep của bạn hỗ trợ biểu thức Perl:

grep -Po '(?<=href=")[^"]*(?=")'
  • (?<=href=")(?=")lookaround biểu cho hrefthuộc tính. Điều này cần -Ptùy chọn.
  • -o in văn bản phù hợp.

Ví dụ:

$ 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
...

Như thường lệ, không có gì đảm bảo rằng đây là các URI hợp lệ hoặc HTML mà bạn phân tích cú pháp sẽ hợp lệ.


8

Là một thay thế không regex , sử dụng con :

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

Sẽ tìm thấy tất cả các ayếu tố có hrefthuộc tính, sau đó hiển thị giá trị của hrefthuộc tính.

Để cài đặt pup, bạn cần Go (ngôn ngữ lập trình):

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

Ưu điểm của giải pháp này là nó không phụ thuộc vào HTML được định dạng chính xác .


1
+1 cho pup, thời gian để cài đặt nó ....
Mark K Cowan

Bạn có thể đặt chúng trong tập tin là tốt. pup 'a.classname[href] attr{href}' < tut.html >links.md
Ahmad Awais

1

Tôi đã tìm thấy một giải pháp ở đây là IMHO đơn giản hơn nhiều và có khả năng nhanh hơn những gì được đề xuất ở đây. Tôi đã điều chỉnh một chút để hỗ trợ các tệp https. Nhưng phiên bản TD; TR là ...

PS: Bạn có thể thay thế URL trang web bằng một đường dẫn đến một tệp và nó sẽ hoạt động theo cùng một cách.

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

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

Nếu bạn chỉ muốn xem các liên kết thay vì đặt chúng vào một tệp, thì hãy thử điều này thay vì ...

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

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

Kết quả sẽ trông giống như sau ...

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.

Đối với trường hợp sử dụng của tôi, điều này làm việc tốt. Nhưng hãy cẩn thận với thực tế là ngày nay, mọi người thêm các liên kết như src = "// blah.tld" cho URI CDN của các thư viện. Tôi không muốn nhìn thấy những người trong các liên kết lấy.

Không cần phải cố gắng kiểm tra for href hoặc các nguồn khác cho các liên kết vì "lynx -dump" theo mặc định sẽ trích xuất tất cả các liên kết có thể nhấp từ một trang nhất định. Vì vậy, suy nghĩ duy nhất bạn cần làm sau đó là phân tích kết quả của "lynx -dump" bằng cách sử dụng grep để có được phiên bản thô sạch hơn cho cùng kết quả.


Nhưng câu hỏi nói rằng URL trích xuất URL từ một tệp HTML [trông giống như] (ví dụ), KHÔNG phải trích xuất URL từ một trang web. Nếu câu trả lời của bạn có thể được sử dụng đối với một tệp trên máy cục bộ, hãy giải thích làm thế nào. Xin vui lòng không trả lời trong các ý kiến; chỉnh sửa câu trả lời của bạn để làm cho nó rõ ràng và đầy đủ hơn.
G-Man nói 'Phục hồi Monica'

1
Bạn có thể thay thế URL bằng tên tệp.
asiby

@ G-Man, tại sao -1? Bạn cần phải tự thử mã và thấy rằng nó cũng hoạt động cho các tệp cục bộ. Tôi đã thêm rằng làm rõ trong trường hợp nó không rõ ràng.
asiby

Điều này thực sự tiện dụng .. nếu bạn đang sử dụng với xargs thì đáng để thêm | sắp xếp | uniq để cắt các liên kết trùng lặp.
Stuart Axon

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

... Có lẽ sẽ làm khá tốt. Như đã viết, nó in:

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

Nếu điều quan trọng là bạn chỉ khớp các liên kết và trong số các tên miền cấp cao nhất đó, bạn có thể thực hiện:

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

... Hoặc một cái gì đó tương tự - mặc dù đối với một số seds, bạn có thể cần phải thay thế một ký tự \newline theo nghĩa đen cho mỗi hai ns cuối cùng .

Như đã viết, lệnh trên in ra:

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

... Và cho cả hai trường hợp (nhưng có lẽ hữu ích nhất với cái sau), bạn có thể giải quyết một |sort -ubộ lọc đến cuối để lấy danh sách sorted và bỏ các bản sao.



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

Tôi không chắc chắn rằng những trích dẫn thông minh trên mạng đó là những gì bạn dự định ở đó - có lẽ là trích dẫn "nhân đôi" thường xuyên?
Jeff Schaller
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.