2011-07-14 4 views
10

का उपयोग कर किसी वेबपृष्ठ के सभी लिंक प्राप्त करना मैं रूबी का उपयोग करके किसी वेबपृष्ठ के प्रत्येक बाहरी लिंक को पुनर्प्राप्त करने का प्रयास कर रहा हूं। मैं इस regex के साथ String.scan उपयोग कर रहा हूँ:रूबी

/href="https?:[^"]*|href='https?:[^']*/i 

फिर, मैं href हिस्से को हटाने के gsub उपयोग कर सकते हैं:

str.gsub(/href=['"]/) 

यह ठीक काम करता है, लेकिन मुझे यकीन है कि अगर यह संदर्भ में कुशल है नहीं कर रहा हूँ प्रदर्शन का क्या यह उपयोग करने के लिए ठीक है या मुझे एक और विशिष्ट पार्सर (उदाहरण के लिए, नोकोगिरी) के साथ काम करना चाहिए? किस तरह से बेहतर है?

धन्यवाद!

+4

कृपया नियमित अभिव्यक्तियों के साथ HTML को पार्स करने का प्रयास न करें, एक HTML पार्सर आपको बेहतर सेवा प्रदान करेगा। –

+0

@ एमयू क्या आप मुझे समझा सकते हैं क्यों? –

+1

क्योंकि एचटीएमएल पार्सिंग आपके मुकाबले अधिक जटिल है, शायद आपको लगता है कि वहां बहुत सारे टूटी हुई एचटीएमएल हैं जो साधारण नियमित अभिव्यक्तियों को संभाल नहीं पाएंगे: http://stackoverflow.com/questions/4231382/regular-expression-pattern- मेल-इन-स्ट्रिंग/4234491 # 4234491 –

उत्तर

3

आप अपने पैटर्न में समूहों का उपयोग क्यों नहीं करते? उदा।

/http[s]?:\/\/(.+)/i 

तो पहला समूह पहले से ही लिंक होगा जिसे आपने खोजा था।

1

क्या आप अपने रेगेक्स में समूह डाल सकते हैं? यही कारण है कि करने के लिए 1 2. के बजाय

+0

अब मैं रेगेक्स सीख रहा हूं। मैं समूहों में एक नज़र डालेगा। धन्यवाद! –

15

नियमित अभिव्यक्ति का उपयोग करते हुए एक त्वरित और गंदे स्क्रिप्ट के लिए ठीक है अपने रेगुलर एक्सप्रेशन को कम करेगा, लेकिन Nokogiri उपयोग करने के लिए बहुत सरल है:

require 'nokogiri' 
require 'open-uri' 

fail("Usage: extract_links URL [URL ...]") if ARGV.empty? 

ARGV.each do |url| 
    doc = Nokogiri::HTML(open(url)) 
    hrefs = doc.css("a").map do |link| 
    if (href = link.attr("href")) && !href.empty? 
     URI::join(url, href) 
    end 
    end.compact.uniq 
    STDOUT.puts(hrefs.join("\n")) 
end 

तुम सिर्फ विधि चाहते हैं, इसे अपनी आवश्यकताओं के लिए थोड़ा सा प्रतिक्रिया दें:

def get_links(url) 
    Nokogiri::HTML(open(url).read).css("a").map do |link| 
    if (href = link.attr("href")) && href.match(/^https?:/) 
     href 
    end 
    end.compact 
end 
+0

क्या आप मुझे फायदे बता सकते हैं? कोड regex और स्कैन के मुकाबले अधिक जटिल लग रहा है। मुझे यह जानकर भी उत्सुकता है कि कौन सा समाधान तेज है। –

+0

@ टोकलैंड, मुझे लगता है कि आप नोकोगिरी :: एचटीएमएल चाहते हैं। केवल पूर्ण लिंक निकालने की आवश्यकता को भी ध्यान दें। –

6

Mechanize हुड के नीचे Nokogiri उपयोग करता है लेकिन HTML पार्स करने, लिंक सहित के लिए निर्मित ब्योरा दिया है:

require 'mechanize' 

agent = Mechanize.new 
page = agent.get('http://example.com/') 

page.links_with(:href => /^https?/).each do |link| 
    puts link.href 
end 

एक पार्सर का उपयोग आम तौर पर हमेशा एचटीएमएल पार्स करने के लिए नियमित अभिव्यक्ति का उपयोग कर से बेहतर है। यह स्टैक ओवरफ्लो पर अक्सर पूछे जाने वाले प्रश्न हैं, this सबसे प्रसिद्ध उत्तर होने के साथ। यह एक केस क्यों है? चूंकि एक मजबूत नियमित अभिव्यक्ति का निर्माण करना जो एचटीएमएल के वास्तविक-विश्व विविधताओं को संभाल सकता है, कुछ मान्य नहीं हैं, एक साधारण पार्सिंग समाधान से बहुत मुश्किल और अंततः अधिक जटिल है जो ब्राउज़र में प्रस्तुत करने वाले सभी पृष्ठों के लिए काम करेगा।

+0

मैं मानता हूं कि जब आपको HTML को पार्स करने की आवश्यकता होती है तो आप regexes का उपयोग नहीं करना चाहते हैं। लेकिन इस मामले में मुझे लगता है कि एक रेगेक्स पर्याप्त होगा, क्योंकि आप एचटीएमएल की अनियमितता के साथ परेशानी में नहीं आते हैं (क्योंकि इसमें कोई पुनरावर्तन शामिल नहीं है)। क्या आप एक (गैर-प्रदूषित) उदाहरण के बारे में सोच सकते हैं जहां यह रेगेक्स (प्रश्न में मेरी टिप्पणी में उल्लिखित मेरे सुधार के साथ) असफल हो जाएगा? – markijbema

+0

मैं आपके समाधान को बेहतर बीटीडब्ल्यू पसंद करता हूं, यह छोटा और पठनीय है, लेकिन मुझे वास्तव में पूर्ण सत्य नहीं लगता है, जैसे 'आप रेगेक्स के साथ एचटीएमएल को छूएं नहीं'। – markijbema

+0

@markijbema मैंने व्याख्या करने के लिए थोड़ा सा जोड़ा है। यहां एक मामला है जो मैंने देखा है: 'foo'। कभी-कभी वहां नई लाइनें भी होती हैं। –

4

मैं नोकोगिरी का बड़ा प्रशंसक हूं, लेकिन पहिया को फिर से क्यों शुरू कर रहा हूं?

URI::extract(str[, schemes][,&blk]) 

डॉक्स से:: एक स्ट्रिंग से

अर्क यूआरआई

रूबी के URI मॉड्यूल पहले से ही यह करने के लिए extract विधि है। यदि ब्लॉक दिया गया है, तो सभी मिलान किए गए यूआरआई के माध्यम से पुनरावृत्त होता है। यदि ब्लॉक दिया गया है या मैचों के साथ सरणी है तो शून्य वापस आता है।

require "uri" 

URI.extract("text here http://foo.example.org/bla and here mailto:[email protected] and here also.") 
# => ["http://foo.example.com/bla", "mailto:[email protected]"] 

आप Nokogiri का उपयोग डोम चलने के लिए और सभी टैग है कि यूआरएल खींच, या यह सिर्फ पाठ निकालते हैं और यह URI.extract के पास है, या बस URI.extract यह सब करते हैं सकता है।

और, रेगेक्स पैटर्न के बजाय, नोकोगिरी जैसे पार्सर का उपयोग क्यों करें?चूंकि HTML, और XML को कई अलग-अलग तरीकों से स्वरूपित किया जा सकता है और फिर भी पृष्ठ पर सही ढंग से प्रस्तुत किया जा सकता है या डेटा को प्रभावी ढंग से स्थानांतरित कर सकता है। जब खराब मार्कअप स्वीकार करने की बात आती है तो ब्राउजर बहुत क्षमा कर रहे हैं। दूसरी तरफ, रेगेक्स पैटर्न, "स्वीकार्यता" की बहुत सीमित श्रेणियों में काम करते हैं, जहां उस श्रेणी को परिभाषित किया जाता है कि आप मार्कअप में विविधता की अपेक्षा करते हैं या इसके विपरीत, आप कितनी अच्छी तरह से अनुमान लगा सकते हैं कि आपका पैटर्न गलत कैसे हो सकता है अप्रत्याशित पैटर्न के साथ प्रस्तुत किया।

एक पार्सर रेगेक्स की तरह काम नहीं करता है। यह दस्तावेज़ का आंतरिक प्रतिनिधित्व बनाता है और उसके बाद चलता है। यह परवाह नहीं करता कि फ़ाइल/मार्कअप कैसे निर्धारित किया जाता है, यह डीओएम के आंतरिक प्रतिनिधित्व पर अपना काम करता है। नोकोगिरी एचटीएमएल को संभालने के लिए अपने पार्सिंग को आराम देता है, क्योंकि एचटीएमएल खराब लिखे जाने के लिए कुख्यात है। इससे हमें मदद मिलती है क्योंकि अधिकांश गैर-मान्य एचटीएमएल नोकोगिरी इसे ठीक कर सकते हैं। कभी-कभी मुझे कुछ ऐसा सामना करना पड़ेगा जो इतनी बुरी तरह लिखा गया है कि नोकोगिरी इसे ठीक से ठीक नहीं कर सकता है, इसलिए मुझे इसे नोकोगिरी में जाने से पहले एचटीएमएल को ट्वीक करके इसे मामूली झुका देना होगा; पैटर्न का उपयोग करने की कोशिश करने के बजाय, मैं अभी भी पार्सर का उपयोग करूंगा।