2010-10-01 14 views
8

Sto mirroring di alcuni siti Web interni a scopo di backup. A partire da ora io fondamentalmente uso questo codice C#:Conversione C# rispetto ai collegamenti assoluti nella stringa HTML

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

Questa scarica appena fondamentalmente l'html e in un array di byte. Questo è quello che voglio. Il problema però è che i collegamenti all'interno dell'html sono per lo più relativi, non assoluti.

Fondamentalmente voglio aggiungere qualunque sia il completo http://domain.is prima del collegamento relativo per convertirlo in un collegamento assoluto che reindirizzerà al contenuto originale. Fondamentalmente mi preoccupo solo di href = e src =. Esiste un'espressione regolare che coprirà alcuni dei casi di base?

Edit [Il mio tentativo]:

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

duplicati di http://stackoverflow.com/questions/3836644/c-convert-relativo-to-absolute-links-in-html-string/3836790 # 3836790 che hai chiesto prima oggi! –

risposta

8

La soluzione più robusta sarebbe quella di utilizzare il HTMLAgilityPack come altri hanno suggerito. Tuttavia una soluzione ragionevole utilizzando le espressioni regolari è possibile utilizzando il Replace overload che accetta un delegato MatchEvaluator, come segue:

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); 

Le ricerche di esempio di cui sopra per gli attributi di nome src e href che contengono valori doppia citati iniziano con una barra. Per ciascuna corrispondenza, viene utilizzato il metodo statico Uri.TryCreate per determinare se il valore è un uri relativo valido.

Si noti che questa soluzione non gestisce valori di attributo con quotatura singola e sicuramente non funziona su HTML non formattato con valori non quotati.

+1

Ho aggiunto una modifica che funziona almeno nei miei pochi casi di test. Guardando le cose regex, sembra abbastanza simile, ma il tuo codice sembra molto più complicato. Onestamente non ho mai usato MatchEvaluator e le cose dei delegati; il tuo codice è migliore? – Gary

+0

L'utilizzo di MatchEvaluator consente di semplificare notevolmente il modello regex e utilizzare invece il metodo Uri.TryCreate molto più robusto. Una regex che corrisponda a tutti i possibili URI sarebbe estremamente complessa. –

+0

Che ne dici delle prestazioni? E grazie per la risposta! – Gary

0

penso url è di tipo stringa. Utilizzare Uri invece con un URI di base che punta al tuo dominio:

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

Questo cambia i collegamenti all'interno dell'html in myUri da relativo a assoluto, oppure è solo una pratica migliore per l'utilizzo di WebClient? – Gary

1

Anche se questo potrebbe non essere il più robusto di soluzioni dovrebbe ottenere il lavoro fatto.

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

Si dovrebbe usare HtmlAgility pacchetto per caricare il codice HTML, accedere a tutte le HREF usarlo, e quindi utilizzare la classe Uri convertire da relativo ad assoluto, se necessario.

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

+0

ho provato il tuo esempio, ma sembra che ci sia un bug. se ho un baseUrl come 'http: // ww.baseurl.com/somedir' e provo a creare un percorso absolut aggiungendo'/login.php' usando il tuo metodo, ottengo 'http://ww.baseurl.com/login.php' invece di 'http: // ww.baseurl.com/somedir/login.php' – Smith

1

È possibile utilizzare il HTMLAgilityPack ottenere questo risultato. Si potrebbe fare qualcosa in questo (non testato) linee:

  • caricare l'URL
  • Selezionare tutti i link
  • carico il collegamento in una Uri e verificare se è relativo Se relativa convertirlo in assoluto
  • Aggiornare il valore di collegamenti con il nuovo uri
  • salvare il file

Ecco alcuni esempi:

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; 

che con il Regex approccio basata su è probabilmente (non testata) mappable a:

 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); 

Vorrei anche consigliare non utilizzare Regex qui, ma di applicare l'Uri trucco per un certo codice usando un DOM, forse XmlDocument (se xhtml) o HTML Agility Pack (altrimenti), guardando tutti gli attributi //@src o //@href.

0

Basta utilizzare questa funzione

'# 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

funzione semplice

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

So che questa è una domanda più vecchio, ma ho capito come si fa con un abbastanza semplice espressione regolare. Funziona bene per me. Gestisce http/https e anche relativo-relativo e corrente-relativo alla directory.

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

questo è quello che stai cercando, questo frammento di codice in grado di convertire tutti i relativi URL per assoluta all'interno di qualsiasi codice 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