2010-10-01 2 views
8

Je reflète certains sites Web internes à des fins de sauvegarde. En ce moment j'utilise essentiellement ce code C#:C# Conversion relative aux liens absolus dans la chaîne HTML

System.Net.WebClient client = new System.Net.WebClient(); 
byte[] dl = client.DownloadData(url); 

Ce télécharge juste fondamentalement le code html et dans un tableau d'octets. C'est ce que je veux. Le problème est cependant que les liens au sein du html sont la plupart du temps relatifs, pas absolus.

Je veux fondamentalement ajouter n'importe quel plein http://domain.is avant le lien relatif comme pour le convertir en un lien absolu qui redirigera vers le contenu original. Je suis fondamentalement juste concerné par href = et src =. Existe-t-il une expression regex qui couvrira certains des cas de base?

Modifier [Ma tentative]:

public static string RelativeToAbsoluteURLS(string text, string absoluteUrl) 
{ 
    if (String.IsNullOrEmpty(text)) 
    { 
     return text; 
    } 

    String value = Regex.Replace(
     text, 
     "<(.*?)(src|href)=\"(?!http)(.*?)\"(.*?)>", 
     "<$1$2=\"" + absoluteUrl + "$3\"$4>", 
     RegexOptions.IgnoreCase | RegexOptions.Multiline); 

    return value.Replace(absoluteUrl + "/", absoluteUrl); 
} 
+0

en double de http://stackoverflow.com/questions/3836644/c-convert-relatif-aux-liens-absolus-en-html-string/3836790 # 3836790 que vous avez demandé plus tôt aujourd'hui! –

Répondre

8

La solution la plus robuste serait d'utiliser le HTMLAgilityPack comme d'autres l'ont suggéré. Cependant, une solution raisonnable en utilisant des expressions régulières est possible en utilisant la surcharge Replace qui prend un délégué MatchEvaluator, comme suit:

var baseUri = new Uri("http://test.com"); 
var pattern = @"(?<name>src|href)=""(?<value>/[^""]*)"""; 
var matchEvaluator = new MatchEvaluator(
    match => 
    { 
     var value = match.Groups["value"].Value; 
     Uri uri; 

     if (Uri.TryCreate(baseUri, value, out uri)) 
     { 
      var name = match.Groups["name"].Value; 
      return string.Format("{0}=\"{1}\"", name, uri.AbsoluteUri); 
     } 

     return null; 
    }); 
var adjustedHtml = Regex.Replace(originalHtml, pattern, matchEvaluator); 

Les recherches ci-dessus des échantillons pour les attributs nommés src et href qui contiennent des valeurs doubles cotées en commençant par une barre oblique. Pour chaque correspondance, la méthode statique Uri.TryCreate est utilisée pour déterminer si la valeur est un uri relatif valide.

Notez que cette solution ne gère pas les valeurs d'attribut entre guillemets simples et ne fonctionne certainement pas sur du HTML mal formé avec des valeurs non protégées.

+1

J'ai ajouté une modification qui fonctionne au moins dans mes quelques cas de test. En regardant les choses regex, ça a l'air assez similaire, mais votre code a l'air beaucoup plus compliqué. Honnêtement, je n'ai jamais utilisé le MatchEvaluator et les trucs des délégués; votre code est-il meilleur? – Gary

+0

L'utilisation d'un outil MatchEvaluator vous permet de simplifier considérablement le modèle regex et d'utiliser à la place la méthode Uri.TryCreate beaucoup plus robuste. Une expression rationnelle qui correspond à tous les URI possibles serait extrêmement complexe. –

+0

Que diriez-vous de la performance sage? Et merci pour la réponse! – Gary

0

Je pense que url est de type chaîne. Utilisez Uri au lieu d'un uri de base pointant vers votre domaine:

Uri baseUri = new Uri("http://domain.is"); 
Uri myUri = new Uri(baseUri, url); 

System.Net.WebClient client = new System.Net.WebClient(); 
byte[] dl = client.DownloadData(myUri); 
+0

Est-ce que cela change les liens dans le code html de myUri par rapport à absolute, ou est-ce juste une meilleure pratique pour utiliser le WebClient? – Gary

1

Bien que cela puisse ne pas être le plus robuste des solutions qu'il devrait faire le travail.

var host = "http://domain.is"; 
var someHtml = @" 
<a href=""/some/relative"">Relative</a> 
<img src=""/some/relative"" /> 
<a href=""http://domain.is/some/absolute"">Absolute</a> 
<img src=""http://domain.is/some/absolute"" /> 
"; 


someHtml = someHtml.Replace("src=\"" + host,"src=\""); 
someHtml = someHtml.Replace("href=\"" + host,"src=\""); 
someHtml = someHtml.Replace("src=\"","src=\"" + host); 
someHtml = someHtml.Replace("href=\"","src=\"" + host); 
5

Vous devez utiliser pack HtmlAgility pour charger le code HTML, accéder à toutes les HREF en utilisant, puis utiliser la classe Uri pour convertir par rapport à absolu si nécessaire.

Voir par exemple http://blog.abodit.com/2010/03/a-simple-web-crawler-in-c-using-htmlagilitypack/

+0

J'ai essayé votre exemple, mais il semble y avoir un bug. si j'ai une baseUrl comme 'http: // ww.baseurl.com/somedir' et que j'essaie de créer un chemin absolu en ajoutant'/login.php' en utilisant votre méthode, j'obtiens 'http://www.baseurl.com/login.php' au lieu de 'http: // ww.baseurl.com/somedir/login.php' – Smith

1

Vous pouvez utiliser le HTMLAgilityPack accomplir cette tâche. Vous feriez quelque chose le long de ces (non testé) lignes:

  • Charger l'URL
  • Sélectionner tous les liens
  • Charger le lien dans une Uri et vérifier si elle est relative Si elle par rapport converti à absolu
  • Mise à jour de la valeur des liens avec la nouvelle uri
  • enregistrer le fichier

Voici quelques exemples:

Relative to absolute paths in HTML (asp.net)

http://htmlagilitypack.codeplex.com/wikipage?title=Examples&referringTitle=Home

http://blog.abodit.com/2010/03/a-simple-web-crawler-in-c-using-htmlagilitypack/

5
Uri WebsiteImAt = new Uri(
     "http://www.w3schools.com/media/media_mimeref.asp?q=1&s=2,2#a"); 
string href = new Uri(WebsiteImAt, "/something/somethingelse/filename.asp") 
     .AbsoluteUri; 
string href2 = new Uri(WebsiteImAt, "something.asp").AbsoluteUri; 
string href3 = new Uri(WebsiteImAt, "something").AbsoluteUri; 

qui avec votre Regex approche fondée sur est probablement (non testé) cartographiables à:

 String value = Regex.Replace(text, "<(.*?)(src|href)=\"(?!http)(.*?)\"(.*?)>", match => 
      "<" + match.Groups[1].Value + match.Groups[2].Value + "=\"" 
       + new Uri(WebsiteImAt, match.Groups[3].Value).AbsoluteUri + "\"" 
       + match.Groups[4].Value + ">",RegexOptions.IgnoreCase | RegexOptions.Multiline); 

Je conseille aussi pas utiliser Regex ici, mais d'appliquer le Uri astuce à un code en utilisant un DOM, peut-être XmlDocument (si xhtml) ou le HTML Agility Pack (autrement), en regardant tous les attributs //@src ou //@href.

0

Il suffit d'utiliser cette fonction

'# converts relative URL ro Absolute URI 
    Function RelativeToAbsoluteUrl(ByVal baseURI As Uri, ByVal RelativeUrl As String) As Uri 
     ' get action tags, relative or absolute 
     Dim uriReturn As Uri = New Uri(RelativeUrl, UriKind.RelativeOrAbsolute) 
     ' Make it absolute if it's relative 
     If Not uriReturn.IsAbsoluteUri Then 
      Dim baseUrl As Uri = baseURI 
      uriReturn = New Uri(baseUrl, uriReturn) 
     End If 
     Return uriReturn 
    End Function 
0

Fonction simple

public string ConvertRelativeUrlToAbsoluteUrl(string relativeUrl) 
{ 

if (Request.IsSecureConnection) 
    return string.Format("https://{0}{1}", Request.Url.Host, Page.ResolveUrl(relativeUrl)); 
else 
    return string.Format("http://{0}{1}", Request.Url.Host, Page.ResolveUrl(relativeUrl)); 

} 
0

Je sais que c'est une question ancienne, mais je compris comment le faire avec un regex assez simple. Cela fonctionne bien pour moi. Il gère http/https et aussi relatif à la racine et relatif au répertoire courant.

var host = "http://www.google.com/"; 
var baseUrl = host + "images/"; 
var html = "<html><head></head><body><img src=\"/images/srpr/logo3w.png\" /><br /><img src=\"srpr/logo3w.png\" /></body></html>"; 
var regex = "(?<=(?:href|src)=\")(?!https?://)(?<url>[^\"]+)"; 
html = Regex.Replace(
    html, 
    regex, 
    match => match.Groups["url"].Value.StartsWith("/") 
     ? host + match.Groups["url"].Value.Substring(1) 
     : baseUrl + match.Groups["url"].Value); 
0

c'est ce que vous cherchez, cet extrait de code peut convertir toutes les URL relatives à absolue à l'intérieur du code HTML:

Private Function ConvertALLrelativeLinksToAbsoluteUri(ByVal html As String, ByVal PageURL As String) 
    Dim result As String = Nothing 
    ' Getting all Href 
    Dim opt As New RegexOptions 
    Dim XpHref As New Regex("(href="".*?"")", RegexOptions.IgnoreCase) 
    Dim i As Integer 
    Dim NewSTR As String = html 
    For i = 0 To XpHref.Matches(html).Count - 1 
     Application.DoEvents() 
     Dim Oldurl As String = Nothing 
     Dim OldHREF As String = Nothing 
     Dim MainURL As New Uri(PageURL) 
     OldHREF = XpHref.Matches(html).Item(i).Value 
     Oldurl = OldHREF.Replace("href=", "").Replace("HREF=", "").Replace("""", "") 
     Dim NEWURL As New Uri(MainURL, Oldurl) 
     Dim NewHREF As String = "href=""" & NEWURL.AbsoluteUri & """" 
     NewSTR = NewSTR.Replace(OldHREF, NewHREF) 
    Next 
    html = NewSTR 
    Dim XpSRC As New Regex("(src="".*?"")", RegexOptions.IgnoreCase) 
    For i = 0 To XpSRC.Matches(html).Count - 1 
     Application.DoEvents() 
     Dim Oldurl As String = Nothing 
     Dim OldHREF As String = Nothing 
     Dim MainURL As New Uri(PageURL) 
     OldHREF = XpSRC.Matches(html).Item(i).Value 
     Oldurl = OldHREF.Replace("src=", "").Replace("src=", "").Replace("""", "") 
     Dim NEWURL As New Uri(MainURL, Oldurl) 
     Dim NewHREF As String = "src=""" & NEWURL.AbsoluteUri & """" 
     NewSTR = NewSTR.Replace(OldHREF, NewHREF) 
    Next 
    Return NewSTR 
End Function