2016-01-06 73 views
2

我想使用Python獲取給定「根」URL(在列表中)的域中的所有鏈接。假設給定了一個URL http://www.example.com這應該返回與根URL相同的域的這個頁面上的所有鏈接,然後對訪問它們的這些鏈接中的每一個進行遞歸,並提取同一個域的所有鏈接等等。我的意思是相同的域名是如果給出http://www.example.com我想要回的唯一鏈接是http://www.example.com/something,http://www.example.com/somethingelse ...任何外部如http://www.otherwebsite.com應該被丟棄。我如何使用Python來做到這一點?如何使用Python獲取域中的所有鏈接?

編輯:我做了一個嘗試使用lxml。我不認爲這是完全可行的,我不知道如何考慮到已處理頁面的鏈接(導致無限循環)。

import urllib 
import lxml.html 

#given a url returns list of all sublinks within the same domain 
def getLinks(url): 
     urlList = [] 
     urlList.append(url) 
     sublinks = getSubLinks(url) 
     for link in sublinks: 
       absolute = url+'/'+link 
       urlList.extend(getLinks(absolute)) 
     return urlList 

#determine whether two links are within the same domain 
def sameDomain(url, dom): 
    return url.startswith(dom) 

#get tree of sublinks in same domain, url is root 
def getSubLinks(url): 
    sublinks = [] 
    connection = urllib.urlopen(url) 
    dom = lxml.html.fromstring(connection.read()) 
    for link in dom.xpath('//a/@href'): 
       if not (link.startswith('#') or link.startswith('http') or link.startswith('mailto:')): 
         sublinks.append(link) 
    return sublinks 

+2

從問題標籤,你似乎已經知道要使用什麼。也許你可以展示你的嘗試,否則我認爲這個問題太籠統了。有圍繞如[scrapy](http://scrapy.org/)的網頁抓取框架可能會幫助你。 – mhawke

+0

這個問題很困難,因爲頁面中的某些鏈接沒有被協議作爲前綴並提供本地路徑。 「..」是一個有效的URL。你想遵循什麼而不是? –

+0

我只想跟隨以URL爲前綴的任何內容。但是,一些相關鏈接沒有以根URL作爲前綴,但是如果我在它們前面加了根URL,它就會有效。我也想要這些。 –

回答

-1

從你的問題的標籤,我假設你使用的是美味的湯。 首先,您顯然需要下載網頁,例如使用urllib.request。做完之後,將內容放在一個字符串中,然後將它傳遞給Beautiful Soup。之後,你可以找到與soup.find_all('a')的所有鏈接,假設湯是你美麗的湯對象。之後,您只需檢查hrefs:

最簡單的版本將檢查「http://www.example.com」是否在href中,但不會捕獲相對鏈接。我猜想一些狂野的正則表達式可以做到(找到所有與「www.example.com」或以「/」開頭或以「?」(PHP)開頭),或者你可能會尋找所有包含www的東西,但不是www.example.com並放棄它等等。正確的策略可能取決於您正在抓取的網站,並且是編碼風格。

-1

您可以使用正則表達式過濾出這樣的鏈接

<a\shref\=\"(http\:\/\/example\.com[^\"]*)\" 

取上述正則表達式作爲參考,並開始編寫基於該腳本。

1
import sys 
import requests 
import hashlib 
from bs4 import BeautifulSoup 
from datetime import datetime 

def get_soup(link): 
    """ 
    Return the BeautifulSoup object for input link 
    """ 
    request_object = requests.get(link, auth=('user', 'pass')) 
    soup = BeautifulSoup(request_object.content) 
    return soup 

def get_status_code(link): 
    """ 
    Return the error code for any url 
    param: link 
    """ 
    try: 
     error_code = requests.get(link).status_code 
    except requests.exceptions.ConnectionError: 
     error_code = 
    return error_code 

def find_internal_urls(lufthansa_url, depth=0, max_depth=2): 
    all_urls_info = [] 
    status_dict = {} 
    soup = get_soup(lufthansa_url) 
    a_tags = soup.findAll("a", href=True) 

    if depth > max_depth: 
     return {} 
    else: 
     for a_tag in a_tags: 
      if "http" not in a_tag["href"] and "/" in a_tag["href"]: 
       url = "http://www.lufthansa.com" + a_tag['href'] 
      elif "http" in a_tag["href"]: 
       url = a_tag["href"] 
      else: 
       continue 
      status_dict["url"] = url 
      status_dict["status_code"] = get_status_code(url) 
      status_dict["timestamp"] = datetime.now() 
      status_dict["depth"] = depth + 1 
      all_urls_info.append(status_dict) 
    return all_urls_info 
if __name__ == "__main__": 
    depth = 2 # suppose 
    all_page_urls = find_internal_urls("someurl", 2, 2) 
    if depth > 1: 
     for status_dict in all_page_urls: 
      find_internal_urls(status_dict['url']) 

上面段包含從漢莎arlines網站報廢網址必要的模塊。此處唯一附加的是您可以指定要遞歸刮取的深度。

+0

這很有道理,但這是如何遞歸的?它似乎只找到第一個「級別」的鏈接。 –

+0

您添加深度,它將搜索到更深的深度。 –

+0

但是find_internal_urls在哪裏被自己實際調用,從而在鏈接上遞歸呢? –

1

以下是我所做的,只是跟隨像http://domain[xxx]這樣的完整網址。快但有點髒。

import requests 
import re 

domain = u"stackoverflow.com" 
http_re = re.compile(u"(http:\/\/" + domain + "[\/\w \.-]*\/?)") 

visited = set([]) 
def visit (url): 
    visited.add (url) 
    extracted_body = requests.get (url).text 
    matches = re.findall (http_re, extracted_body) 
    for match in matches: 
     if match not in visited : 
      visit (match) 

visit(u"http://" + domain)  
print (visited) 
相關問題