Fragensteller
List all links of an Webpage

Frage
-
Hallo zusammen,
ich wollte alle links einer Webseite auflisten. Leider hänge schon schon an elementaren Dingen. Von dotnetpearls fand ich ein Regex Code Beispiel, das ich gerne ausweiten wollte. Das u.g. Beispiel listet tatsächlich schon alle Links einer webseite, aber einige Dinge klappen nicht. Daher habe ich ein paar Fragen:
a) Ich wollte nur einen Teil der Links auflisten. In dem Fall die Links die mit "/wiki/" beginnen. Mein code listet alles wenn nur wiki in der Textzeile steht
b) Ich möchte dann den Stringpart "/wiki/" vom String abschneiden. Das klappt so auch nicht.
c) Ich suche das richtige Anzeigeelement zur Darstellung der Links. Als ziel hätte ich gerne das ich in einer Liste alle verlinkten Texte aufliste, und diese mit dem Link hinterlegt belasse. Also im konkreten Beispile steht unter Wiki dort "Spanien" und wenn ich drauf klicke solte sich der link öffnen. Im Grunde wie ein Browser, aber eigentlich möchte ich rekursiv nochmal das die gleich App aufrufen u. dann auch wieder alle Links listen.
Hier mein Code:
/*
* Created by SharpDevelop.
* User: A692517
* Date: 17.03.2016
* Time: 14:06
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using System.Net;
using System.Text.RegularExpressions;
namespace Srape
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//
// TODO: Add constructor code after the InitializeComponent() call.
//
}
void Button1Click(object sender, EventArgs e)
{
// Scrape links from wikipedia.org
// 1.
// URL: http://en.wikipedia.org/wiki/Main_Page
WebClient w = new WebClient();
System.Net.WebRequest.DefaultWebProxy.Credentials
= System.Net.CredentialCache.DefaultNetworkCredentials;
//WebProxy wp = new WebProxy(" proxy server url here");
string s = w.DownloadString("http://en.wikipedia.org/wiki/Main_Page");
// 2.
foreach (LinkItem i in LinkFinder.Find(s))
{
//Debug.WriteLine(i);
listBox1.Items.Add(i);
}
Console.ReadLine();
}
public struct LinkItem
{
public string Href;
public string Text;
public override string ToString()
{
return Href + "\t" + Text;//\n
}
}
static class LinkFinder
{
public static List<LinkItem> Find(string file)
{
List<LinkItem> list = new List<LinkItem>();
// 1.
// Find all matches in file.
MatchCollection m1 = Regex.Matches(file, @"(<a.*?>.*?</a>)",
RegexOptions.Singleline);
// 2.
// Loop over each match.
foreach (Match m in m1)
{
string value = m.Groups[1].Value;
//listet nur links die mit "/wiki/" anfangen => FEHLER er listet alles auf wenn er nur "wiki" findet
string searchWithinThis = value;
string searchForThis = "/wiki/";
int firstCharacter = searchWithinThis.IndexOf(searchForThis);
if(firstCharacter>0)
{
LinkItem i = new LinkItem();
{
// 3.
// Get href attribute.
Match m2 = Regex.Match(value, @"href=\""(.*?)\""",
RegexOptions.Singleline);
if (m2.Success)
{
i.Href = m2.Groups[1].Value;
}
// 4.
// Remove inner tags from text.
/* string t = Regex.Replace(value, @"\s*<.*?>\s*", "",
RegexOptions.Singleline);
i.Text = t;
*/
//schneidet "serie/" vom Textstring ab=> FEHLER
// string Stg = i.Text;
// Stg.Replace("/wiki/","");
}
list.Add(i);
}
}
return list;
}
}
}
}
Alle Antworten
-
Hi,
ich würd es mal mit dem HtmlAgilityPack probieren.
https://www.nuget.org/packages/HtmlAgilityPack
Wenn Du einen String darauf prüfen willst, ob er mit einer Zeichenfolge beginnt, solltest Du <String>.StartsWith und nicht IndexOf verwenden.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hallo jodahush,
hast Du konkrete Beispiele zu:a) Ich wollte nur einen Teil der Links auflisten. In dem Fall die Links die mit "/wiki/" beginnen. Mein code listet alles wenn nur wiki in der Textzeile steht
Ich kann das nämlich mit dem gegebenen Code nicht nachvollziehen. Um zu prüfen ob eine Zeichenfolge in einem String enthalten ist, gibt es Contains - reicht auch deshalb, weil dir schließlich egal ist an welcher Stelle diese Zeichenfolge steht.
b) Ich möchte dann den Stringpart "/wiki/" vom String abschneiden. Das klappt so auch nicht.
Im Quelltext verwendest Du Replace, ein Remove reicht hier völlig.
c) Ich suche das richtige Anzeigeelement zur Darstellung der Links. Als ziel hätte ich gerne das ich in einer Liste alle verlinkten Texte aufliste, und diese mit dem Link hinterlegt belasse. Also im konkreten Beispile steht unter Wiki dort "Spanien" und wenn ich drauf klicke solte sich der link öffnen. Im Grunde wie ein Browser, aber eigentlich möchte ich rekursiv nochmal das die gleich App aufrufen u. dann auch wieder alle Links listen.
Das geht zum Beispiel mit einem HTML Control, oder generiere einfach eine HTML Seite daraus und reiche diese an den Standard-Browser weiter.
Gruß
- Florian
-
Vielen Dank
C# hat ja eine menge Methoden am String objekt. Das geht mit StartWith und Replace ja schon gut.
Jetzt habe ich die Liste mit den URL, den links und dem Text und würde gerne die verlinkten Texte anzeigen. Ich nehme an das ich dazu das AquilityPack brauche.
Ich nutze SharpDevelop (da kein Admin). Mal sehen ob ich das AgilityPack da drauf kriege.
-
Hallo zusammen,
hier meine bisherige Lösung (Webbrowser wäre vielleicht besser)
struct FilmSerie
{
public int Index;
public string SName;
public string SUrl;
};List<FilmSerie> FilmListe = new List<FilmSerie>();private void button1_Click(object sender, EventArgs e)
{
UrlList.Items.Clear();
var getHtmlWeb = new HtmlWeb();
var document = getHtmlWeb.Load(InputTextBox.Text);
var aTags = document.DocumentNode.SelectNodes("//a");
int counter = 1;
if (aTags != null)
{
foreach (var aTag in aTags)
{// string HTS = aTag.Attributes["href"].Value;
//int Ix = ;
if (aTag.Attributes["href"].Value.IndexOf("erie/") > 0)
{
//Books Book1;
FilmSerie Filmserien;
Filmserien.SName = aTag.InnerHtml;
Filmserien.SUrl = aTag.OuterHtml;
Filmserien.Index = counter;FilmListe.Add(Filmserien);
UrlList.Items.Add(FilmListe[counter - 1].SName);// UrlList.Items.Add(counter + ". " + aTag.InnerHtml + " - " + aTag.OuterHtml); das funktioniert
counter++;
}}
}- Bearbeitet jodahush Sonntag, 27. März 2016 21:23
-
Hallo jodahush,
ich hatte Dich so verstanden, dass Du deine Links separat von der Anzeige auflisten wolltest, z. B. in einem List Control oder ähnlichem. Mein Vorschlag für das Webcontrol bezog sich darauf die Seite anzuzeigen, deine zweite Bedingung unter c).
Selbstverständlich kannst Du auch die Links im Webcontrol anzeigen, dafür musst Du ein einfaches HTML Dokument mit deinen Links darin aufbauen und an das Webcontrol übergeben.
Nach den von Dir genannten Bedingungen würde ich die Links aber eher in einem List Control anzeigen, schließlich hast Du bereits eine Liste von Links und kannst auf anklicken eines Eintrages in der Liste entsprechende Programmabläufe auslösen und das verlinkte Dokument dann im Webcontrol oder im Standard Webbrowser anzeigen (ggfls. vorher daraus die Links entfernen).
Gruß
- Florian
-
Hallo jodahush,
ich kann nicht beurteilen wie gut eine Lösung zu deiner konkreten Anwendung passt. Wenn nur jeweils eine Webseite und deren Links zur Auswahl stehen soll, wird eine "List" wohl hinreichend sein, denkbar wäre natürlich auch die Struktur der Webseite als Baum abzubilden, was z. B. mit einem Tree Control dargestellt werden könnte, ginge aber über das hinaus was Du anfänglich beschriebst und Du müsstest Dir Gedanken darüber machen welche Darstellungstiefe akzeptabel ist und ob diese Tiefe durch den Benutzer einstellbar sein sollte.
Für das beschriebene hatte ich einen Darstellungsvorschlag (listcontrol für die links und webbrowser control zur Darstellung der Webseite) gemacht, andere Möglichkeiten sind natürlich denkbar.
Gruß
- Florian