2016-01-06 50 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) 
相关问题