Entwickler-Ecke

Internet / Netzwerk - Eine URL aus einem Quelltext lesen / Image aus URL laden


Terra23 - So 08.07.12 18:04
Titel: Eine URL aus einem Quelltext lesen / Image aus URL laden
Hi!

Ich habe leider schon wieder ein Problem. Ich habe es bereits geschafft, mit Hilfe der Suche und einigen Threads, den Quellcode einer Seite (z.B. dieser Seite [http://yugioh.wikia.com/wiki/Tour_Guide_From_the_Underworld]) in ein Memo zu laden. Nun möchte ich aus dem Quelltext nur den String auslesen, in dem das Wort "300px-" vorkommt.

Hier mal für euch die Seite mit dem Quelltext zum Nachvollziehen: Klick [http://yugioh.wikia.com/wiki/Tour_Guide_From_the_Underworld]


Es sind auf diesen Wikia-Seiten immer so viele Images und Thumbnails verlinkt, deswegen muss es der folgende Teiltext sein, der "300px-" enthält.

Für diese Beispielseite wäre das diese URL:
http://images4.wikia.nocookie.net/__cb20120531135837/yugioh/images/thumb/9/96/TourGuideFromtheUnderworld-BP01-EN-R-1E.png/300px-TourGuideFromtheUnderworld-BP01-EN-R-1E.png


Leider komme ich mit Pos und Copy nicht wirklich weiter, da ich ja, wie gesagt, nur die URL haben will, die den String "300px-" enthält.


Und wenn ich diese URL dann extrahiert habe, wie kriege ich sie in ein Image geladen?

Kann mir jemand vielleicht ein wenig unter die Arme greifen (gern auch mit passenden Suchbegriffen, sofern diese nicht Pos und Copy sind). ;)


Gruß,

Terra


Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am So 08.07.2012 um 18:34


MDX - So 08.07.12 22:08

Entweder du suchst alle src="URL"-Tags aus dem Quelltext heraus und filterst dann die Adresse raus wo "300px" vorkommt oder wenn es auf jeder Seite der Fall ist, dann filtere von src=" nach " width="300", sollte mit Pos, PosEx und Copy möglich sein.

Aber:
Du kannst hier auch mit Pos und PosEx/Copy nach <link rel="image_src" href=" und " /> filtern und dann die Adresse von 100px mit StringReplace zu 300px umändern.


In ein Image bekommst du Sie geladen, wenn du sie herunterlädst, anders geht das IMHO nicht...


Terra23 - Mo 09.07.12 18:07

Sorry, aber ich bin dazu irgendwie zu dämlich. Ich kann nichtmal die URL des Bildes extrahieren... :(


bummi - Mo 09.07.12 18:10

Du hast die nötigen Suchbegriffe bereits selbst genannt und darum gebeten Dir damit nicht unter die Arme zu greifen.
Das sind Basics die man sich erarbeiten muss....


jaenicke - Mo 09.07.12 18:16

Poste doch einfach mal was du versucht hast. ;-)

Alternativ könntest du einen HTML Parser verwenden, sei es der von den JEDIs (ich glaube da gibt es einen, oder? :gruebel:), der des Internet Explorers oder ein anderer für Delphi.

user profile iconMDX hat folgendes geschrieben Zum zitierten Posting springen:
In ein Image bekommst du Sie geladen, wenn du sie herunterlädst, anders geht das IMHO nicht...
Ja, richtig, wobei man da immer mit Streams arbeiten kann. Herunterladen in den Arbeitsspeicher reicht also. (Nur zur Klarstellung, dass keine Datei benötigt wird, wenn du von Herunterladen schreibst.)


Terra23 - Mo 09.07.12 18:26

Ja, das mache ich gerne.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
procedure TForm1.Button2Click(Sender: TObject);
var S: String;
    Stelle: Integer;
    Start: Integer;
    I: Integer;
    Stop: Integer;
begin
/// Suche im Memo den String "300px-"
Stelle := Pos('300px-', Memo1.Text);

/// Gehe von dort rückwärts bis zum Anfang des Memos...
For I := Stelle DownTo 0 Do
/// bis die ersten " gefunden werden...
If Memo1.Text[I] = '"'
Then Begin
     /// und lege dann den Beginn für den zu kopierenden Textes fest
     Start := I+1;
     Break;
     End;

/// Gehe von Beginn an zum Ende des Memos...
For I := Start To Length(Memo1.Text) Do
/// bis die ersten " gefunden werden...
If Memo1.Text[I] = '"'
Then Begin
     /// und lege dann das Ende des zu kopierenden Textes fest
     Stop := I;
     Break;
     End;

/// Kopiere den String, der sich zwischen START und ENDE befindet und zeige ihn im Label
S := Copy(Memo1.Text, Start, (Stop-Start));
Label1.Caption := S;
end;


Ich weiß, dass die Variable "Start" richtig befüllt wird; das habe ich probiert. Inzwischen weiß ich auch, wo der Fehler lag... ;)

Gruß,

Terra

EDIT: QUELLCODE BEHOBEN!!!

Moderiert von user profile iconNarses: Beiträge zusammengefasst

Hab es jetzt raus. Es darf nicht heißen...


Delphi-Quelltext
1:
To Memo1.Lines.Count                    


... sondern muss heißen...


Delphi-Quelltext
1:
To Length(Memo1.Text)                    


Habe das jetzt mit verschiedenen URLs ausprobiert und es klappt jedes Mal, die URL des Bildes zu extrahieren.



Mal ne andere Frage: Geht das Laden des Quelltextes auch irgendwie schneller? Also im eigentlichen Programm will ich den Text nicht erst in ein Memo laden und dann extrahieren und dann das Bild anzeigen. Es soll für den User so aussehen, als wird nur das Bild gezeigt. Geht das vielleicht, wenn ich den Quelltext in eine Stringlist lade? Wenn ja, wie mache ich das?


haentschman - Mo 09.07.12 20:00

Hallo...
Zitat:
Geht das vielleicht, wenn ich den Quelltext in eine Stringlist lade? Wenn ja, wie mache ich das?

1. Stringlist erzeugen
2. Text in Stringlist (wie beim Memo)
3. damit arbeiten
4. Stringlist freigeben
8)


Terra23 - Mo 09.07.12 20:08

Wäre das so richtig?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TForm1.Button1Click(Sender: TObject);
begin
/// Stream erzeugen
Quellstream := TStringList.Create;
Try
/// Stream füllen
Quellstream.Text := IdHTTP1.Get(Edit1.Text);
MEINE ARBEIT MIT DEM STREAM
Finally
/// Stream freigeben
Quellstream.Free;
End;
end;


Ich habe noch nie wirklich mit dem Try-Finally-End gearbeitet, daher nochmal meine Rückfrage.

Gruß,

Terra

PS: Kann mir jemand erläutern, was Try-Finally-End macht?


MDX - Mo 09.07.12 20:26


Delphi-Quelltext
1:
2:
3:
4:
5:
try
VersucheIrgendwas;
finally
HatFuntkioniertAlsoIrgendwasAnderesMachen;
end;


daneben gibts auch noch


Delphi-Quelltext
1:
2:
3:
4:
5:
try
VersucheIrgendwas;
except
HatNichtFunktioniertAlsoFehlerAbfangen;
end;


Achja, willst du mehr als eine Zeile Code nach try, finally oder except ausführen musst du die Anweisungen alle in einen begin, end Block setzen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
try
begin
[...]
end;
finally
begin
[...]
end;
end;


haentschman - Mo 09.07.12 21:07

Ergänzung:

egal was zwischen try und finally passiert... der finally Block wird immer ausgeführt. Mal angenommen du wölltest deine procedure mit exit verlassen... der finally Block wird dann nach dem exit abgearbeitet und erst dann die procedure verlassen.


Terra23 - Mo 09.07.12 21:13

Danke für eure Hilfe.

Kann mir noch kurz jemand von euch erklären, warum ich keine Bilder laden kann?

Erklärung:
In Label1.Caption steht die URL des Bildes, das ich laden will.

Hier mein aktueller Code:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
ImgStream := TMemoryStream.Create;
Try
 Begin
 IdHTTP1.Get(Label1.Caption, ImgStream);
 ImgStream.Position := 0;
 JvImage1.Picture.Graphic.LoadFromStream(ImgStream);
 End;
Finally;
ImgStream.Free;
End;


Ich würde das Bild gern anzeigen lassen ohne es auf der Festplatte zwischenzuspeichern. Ich hatte zwar einen langen Code gefunden (hier [http://www.delphipraxis.net/299979-post.html]) aber das geht nur für JPGs. Wenn ich ein PNG laden will, führt dies eine Exception herbei (logisch).

Leider kann ich probieren, wie ich will ... ich finde nirgends die passende Antwort...


Narses - Mo 09.07.12 22:46

Moin!

user profile iconMDX hat folgendes geschrieben Zum zitierten Posting springen:
Achja, willst du mehr als eine Zeile Code nach try, finally oder except ausführen musst du die Anweisungen alle in einen begin, end Block setzen:
Für´s Protokoll: Das ist nicht korrekt, das begin/end ist hier überflüssig. Die try-Blöcke sind wie begin eine Klammer. :idea:

Delphi-Quelltext
1:
2:
3:
4:
5:
try
// kein begin/end erforderlich!
finally
// kein begin/end erforderlich!
end;

cu
Narses


bummi - Mo 09.07.12 22:52

Wenn Du ein PNG laden willst musst Du ein TPNGImage erzeugen, dieses aus dem Stream laden und dann Image.Picture.Graphic zuweisen (assign) und wieder freigeben.


Terra23 - Di 10.07.12 00:01

@bummi: Aber sowohl das normale Image als auch das Image aus den Jedi-Komponenten müssten doch eigentlich beide Dateiformate öffnen können. Wenn ich das über den Objektinspektor zuweise, klappt das ja auch. Ich bin verwirrt...

@narses: Danke für die Richtigstellung bezüglich Begin / End...


MDX - Di 10.07.12 00:21

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Moin!Für´s Protokoll: Das ist nicht korrekt, das begin/end ist hier überflüssig. Die try-Blöcke sind wie begin eine Klammer. :idea:

Man lernt immer was dazu :D
Wieder bisschen Quellcode gespart :)


jaenicke - Di 10.07.12 02:38

user profile iconTerra23 hat folgendes geschrieben Zum zitierten Posting springen:
@bummi: Aber sowohl das normale Image als auch das Image aus den Jedi-Komponenten müssten doch eigentlich beide Dateiformate öffnen können. Wenn ich das über den Objektinspektor zuweise, klappt das ja auch. Ich bin verwirrt...
Da gibt es aber die Dateierweiterung als zusätzliche Information. Deshalb kann beim Laden einer gespeicherten Datei automatisch die passende Klasse benutzt werden.

Wenn du aber ein Bild aus einem Stream lädst, gibt es diese Information nicht. Und deshalb musst du die korrekte Klasse selbst zur Erzeugung des Bildobjekts auswählen.


Terra23 - Di 10.07.12 14:17

Hi!

Ich habe jetzt mal die Dateiendung ausgelesen. Das klappt auch einwandfrei. Die Endung speichere ich in der String-Variablen namens "Art" zwischen.

Dann starte ich folgende Abfrage, die eigentlich auch korrekt sein müsste:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
If Art = 'jpg'
Then Begin
     Try
     ImgStream := TMemoryStream.Create;
     IdHTTP1.Get(Label1.Caption, ImgStream);
     ImgStream.Position := 0;
     JPGBild := TJPEGImage.Create;
     JPGBild.LoadFromStream(ImgStream);
     JvImage1.Picture.Assign(JPGBild);
     Finally
     JPGBild.Free;
     ImgStream.Free;
     End;
     End;

If Art = 'png'
Then Begin
     Try
     ImgStream := TMemoryStream.Create;
     IdHTTP1.Get(Label1.Caption, ImgStream);
     ImgStream.Position := 0;
     PNGBild := TPNGImage.Create;
     PNGBild.LoadFromStream(ImgStream);
     JvImage1.Picture.Assign(PNGBild);
     Finally
     PNGBild.Free;
     ImgStream.Free;
     End;
     End;


Wenn ich das Programm dann starten will, bekomme ich die Meldung "Undefinierter Bezeichner: 'TPNGImage'", was ich mir leider nicht erklären kann. Ich dachte, wenn ich die Variablen so definiere...


Delphi-Quelltext
1:
2:
var JPGBild: TJPEGImage;
            PNGBild: TPNGImage;


... dass es dann funktionieren würde.


Kann mich mal jemand bitte auf den richtigen Weg schubsen??


jaenicke - Di 10.07.12 15:50

Du hast die Unit für TPngImage nicht eingebunden, deshalb findet Delphi die Klasse nicht. Die Unit heißt in der Regel PngImage, sei es die von Delphi selbst oder eine fremde.


bummi - Di 10.07.12 15:58

häng mal in eine Deiner Units

Delphi-Quelltext
1:
2:
initialization
RegisterClasses([TIcon, TMetafile, TBitmap, TJPEGImage,TPngImage]);


bzw. was Du davon brauchst.


jaenicke - Di 10.07.12 17:32

Das ist hier nicht das Problem, dann würde die Meldung lauten, dass die Klasse nicht gefunden wurde. Hier handelt es sich nicht um einen Laufzeitfehler sondern um einen Fehler beim Kompilieren. ;-)


bummi - Di 10.07.12 18:02

:bawling: wieder nicht richtig gelesen, sorry ...


Terra23 - Di 10.07.12 19:47

Ich habe mir jetzt mal die Unit "TPNGImage" ausm Netz runtergeladen und zu den anderen Units gepackt. Dann kam die Meldung "Datei nicht gefunden: 'ZLibEx.dcu'", obwohl diese Unit gar nicht unter "Uses" aufgeführt ist.

Muss ich jetzt tatsächlich ne andere Komponente (TPNGImage) suchen und installieren? Die TImage-Komponente aus Delphi 7 kennt doch PNG-Dateien. Warum ist das Ganze jetzt am Ende doch so kompliziert?

Klar, wenn man programmiert, darf man nicht erwarten, dass man alles serviert bekommt, aber wenn eine Komponente schon mit den Dateien umgehen kann, dürfte man dann nicht erwarten, dass die auch funktioniert?

Gruß,

Terra


jaenicke - Di 10.07.12 21:13

Ich habe keine Ahnung welche Komponente du da hast, aber die Standardkomponente, die jetzt mit Delphi mitgeliefert wird, funktioniert bei mir problemlos:
http://www.torry.net/authorsmore.php?id=6929


Terra23 - Di 10.07.12 21:21

Ich verfüge über die Standard-Komponente (TImage) und die aus den JediVCLs (TJvImage). Die Unit "TPNGImage" hatte ich mir "lose" also einzeln heruntergeladen ohne eine Komponente dazu.

Wie installiere ich denn die Komponente, die du verlinkt hast?


jaenicke - Di 10.07.12 21:23

Du entpackst das Zip-Archiv und fügst den Pfad dem Bibliothekspfad hinzu oder die Units dem Projekt.


Terra23 - Di 10.07.12 21:30

Das Programm beschwert sich immer noch über "TPNGImage".

Ich habe den Ordner in die Bibliothek aufgenommen und die Unit ins Programm.

Trotzdem beschwert es sich...


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
procedure TForm1.Button2Click(Sender: TObject);
var ImgStream: TMemoryStream;
    Art: String;
    JPGBild: TJPEGImage;
    PNGBild: TPNGImage; -> hier beschwert sich das Programm (Undefinierter Bezeichner: TPNGImage)
begin
Diverse Aktionen, die für den Fehler irrelevant sind

/// Bestimme die Dateiendung des Bildes (URL steht in Label1.Caption)
Art := Copy(Label1.Caption, J, 3);

/// Wenn es ein JPG ist, lade es...
If Art = 'jpg'
Then Begin
     Try
     ImgStream := TMemoryStream.Create;
     IdHTTP1.Get(Label1.Caption, ImgStream);
     ImgStream.Position := 0;
     JPGBild := TJPEGImage.Create;
     JPGBild.LoadFromStream(ImgStream);
     JvImage1.Picture.Assign(JPGBild);
     Finally
     JPGBild.Free;
     ImgStream.Free;
     End;
     End;

/// Wenn es ein PNG ist, lade es...
If Art = 'png'
Then Begin
     Try
     ImgStream := TMemoryStream.Create;
     IdHTTP1.Get(Label1.Caption, ImgStream);
     ImgStream.Position := 0;
     PNGBild := TPNGImage.Create;
     PNGBild.LoadFromStream(ImgStream);
     JvImage1.Picture.Assign(PNGBild);
     Finally
     PNGBild.Free;
     ImgStream.Free;
     End;
     End;


jaenicke, weißt du da Rat? Das übersteigt echt meine dürftigen Programmierkenntnisse...


jaenicke - Di 10.07.12 21:31

Du musst auch noch die Unit PngImage in die uses Klausel aufnehmen.


Terra23 - Di 10.07.12 21:33

Hab ich doch schon...


Delphi-Quelltext
1:
2:
3:
4:
5:
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
  IdTCPClient, IdHTTP, ShellApi, ExtCtrls, JPEG, JvImage, JvExExtCtrls, PNGImage,
  PNGExtra;


jaenicke - Di 10.07.12 21:35

Ah, tut mir leid, ich habe kurz in die Unit hineingeschaut, die Klasse heißt TPngObject. :idea:


Terra23 - Di 10.07.12 21:42

Vielen Dank, es funktioniert.

Hier nochmal für alle, die zukünftig auf diesen Thread stoßen, die Zusammenfassung:


So lädt man ein JPG aus einem Stream in ein Image:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure TForm1.Button2Click(Sender: TObject);
var ImgStream: TMemoryStream;
    JPGBild: TJPEGImage;
    PNGBild: TPNGObject;
begin
     Try
     ImgStream := TMemoryStream.Create;
     IdHTTP1.Get(/// URL des Bildes, ImgStream);
     ImgStream.Position := 0;
     JPGBild := TJPEGImage.Create;
     JPGBild.LoadFromStream(ImgStream);
     Image1.Picture.Assign(JPGBild);
     Finally
     JPGBild.Free;
     ImgStream.Free;
     End;
     End;


So lädt man ein PNG aus einem Stream in ein Image:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure TForm1.Button2Click(Sender: TObject);
var ImgStream: TMemoryStream;
    JPGBild: TJPEGImage;
    PNGBild: TPNGObject;
begin
     Try
     ImgStream := TMemoryStream.Create;
     IdHTTP1.Get(/// URL des Bildes, ImgStream);
     ImgStream.Position := 0;
     PNGBild := TPNGObject.Create;
     PNGBild.LoadFromStream(ImgStream);
     JvImage1.Picture.Assign(PNGBild);
     Finally
     PNGBild.Free;
     ImgStream.Free;
     End;