الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

إستخراج الروابط من صفحة Html

بدأه herch في 15 ديسمبر 2009 · 8 رد · 1,337 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

يمكننا عن طريق الجافا الوصول إلى كل الوسوم الموجودة في صفحة html، والتعرف على ميزات كل وسم ومحتواه.

في هذا المثال سنتعرف على كيفية استخراج الروابط الموجودة في الوسم <a>، هذا الوسم يتوفر على ميزة href هي التي تحتوي على الرابط.

سنستعمل الفئتين ParserDelegator و ParserCallback.

عندما ننشئ object من فئة ParserDelegator، فإننا نمرر له Reader الذي يقوم بقراءة الملف html، ونمرر له أيضا object من فئة ParserCallback.

الParserDelegator الذي أنشانا يقوم بعمل parsing للملف html وذلك بالنداء على parser خاص بالhtml، هذا الparser يقوم في كل مرة يجد فيها وسما بالنداء على طريقة معينة موجودة في ParserCallback، مثلا عندما يدخل الparser لوسم ما، فإنه ينادي على الطريقة

handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)

وعندما يخرج منه فإنه ينادي على الطريقة

handleEndTag(HTML.Tag t, int pos)

كلتا الطريقتين موجودتان في الفئة ParserCallback.

الآن ما نريد فعله هو استخراج كل الروابط الموجودة في صفحة html وإضافتها إلى ArrayList، لهذا الغرض سنكتب فئة ترث من ParserCallback ونعمل override للطريقة handleStartTag. هذه الأخيرة تنتظر ثلاث arguments، الأول من فئة Tag، وهو يمثل الوسم الذي نحن بصدد الدخول إليه، الargument الثاني هو من فئة MutableAttributeSet، هذه الفئة تعمل تقريبا مثل dictionary، أي أنها عبارة عن أزواج key/value، هذا الargument يحتوي على المزايا ( attributes ) الخاصة بالوسم، الargument الأخير لن نحتاجه.

	class LinkAction extends HTMLEditorKit.ParserCallback {

		@Override
		public void handleStartTag(Tag t, MutableAttributeSet a, int pos) {
			if (t == Tag.A) {
				String href = (String)a.getAttribute(Attribute.HREF);
				if (href != null) {
					links.add(href);
				}
			}
		}
	}

كما سبق وقلنا فإن handleStartTag هي التي ينادي عليها الparser عند الدخول لوسم ما، لذلك فإننا نقوم بoverride ونكتبها لتلبي غرضنا. أولا نتحقق من أن الوسم الحالي هو وسم <a>، إذا كان كذلك فإننا نستخرج الميزة href ونضيفها إلى الArrayList الذي يحتوي على الروابط، أي المتغير links كما في المثال

سنقوم الآن بكتابة البرنامج

public class ExtractLinks {

	private ArrayList<String> links;
	private BufferedReader reader;
	private ParserDelegator delegator;
......

أعلنا ثلاث متغيرات، المتغير الاول من فئة ArrayList هو الذي سيحتوي على الروابط، المتغير الثاني من فئة BufferedReader هو الذي سيقوم بقراءة الملف html، المتغير الثالث من فئة ParserDelegator هو الذي سيقوم بعملية الparsing

	public ExtractLinks(URL url) throws IOException {
		links = new ArrayList<String>();
		reader = new BufferedReader(new InputStreamReader(url.openStream()));
		delegator = new ParserDelegator();
	}

هذا الconstructor ينتظر argument من فئة URL، وهو يمثل عنوان الصفحة html التي سنعمل عليها. داخل الconstructor نقوم بعمل instanciation للمتغيرات، بالنسبة للمتغير من فئة BufferedReader فقد مررنا له InputStreamReader، حيث أن url.openStream() تعيد binary stream بينما BufferedReader عبارة عن character stream، لذلك نستعمل InputStreamReader الذي يحول من binary stream إلى character stream

	public ArrayList<String> extractLinks() throws IOException {
		delegator.parse(reader, new LinkAction(), true);
		return links;
	}

داخل الطريقة extractLinks ننادي على الطريقة parse الخاصة بParserDelegator ونمرر لها الBufferedReader الذي أنشأنا، ثم الفئة التي ترث من ParserCallback والتي كتبناها فوق، وboolean يحدد هل يجب الأخد بعين الإعتبار الcharset أو لا

المثال بالكامل

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML.Attribute;
import javax.swing.text.html.HTML.Tag;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;


public class ExtractLinks {

	private ArrayList<String> links;
	private BufferedReader reader;
	private ParserDelegator delegator;

	public ExtractLinks(URL url) throws IOException {
		links = new ArrayList<String>();
		reader = new BufferedReader(new InputStreamReader(url.openStream()));
		delegator = new ParserDelegator();
	}

	public ArrayList<String> extractLinks() throws IOException {
		delegator.parse(reader, new LinkAction(), true);
		return links;
	}

	class LinkAction extends HTMLEditorKit.ParserCallback {

		@Override
		public void handleStartTag(Tag t, MutableAttributeSet a, int pos) {
			if (t == Tag.A) {
				String href = (String)a.getAttribute(Attribute.HREF);
				if (href != null) {
					links.add(href);
				}
			}
		}
	}

	public static void main(String[] args) {
		try {
			ExtractLinks extract = new ExtractLinks(new URL("http://www.google.com"));
			ArrayList<String> links = extract.extractLinks();
			for (String s : links) {
				System.out.println(s);
			}
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}
}

تم تعديل هذه المشاركة بواسطة herch في 15 ديسمبر 2009 في 23:35

2
#2

كتطبيق لما سبق يمكن عمل برنامج يتحقق من الروابط هل تعمل بشكل جيد أم لا HTML broken link finder

يمكن أيضا عمل web crawler أو web spider

#3

جزاك الله خيرا .

كتطبيق لهذا الشرح الجميل يمكن عمل برنامج لتحميل الموقع بأكمله لنتصفحه فيما بعد بدون إتصال ، أو تحميل الروابط التي تشير إلى ملفات الصوت أو الصور أو أي نوع آخر .

300_130.gif

#4

جزاك الله خيراً على هذا الموضوع الممتاز..

بإمكاننا أيضاً استخدام HtmlUnit لعمل نفس الأمر بالشكل التالي:

WebClient webClient;
webClient = new WebClient(BrowserVersion.FIREFOX_3);

HtmlPage page = webClient.getPage("http://www.yahoo.com");
List<HtmlAnchor> anchors = page.getAnchors();

HtmlAnchor عبارة عن Object متكامل عن الـ Anchor يزودك بكافة المعلومات و بإمكانية تنفيذ نقر عليه أيضاً و الحصول على النتيجة مباشرة..

تحياتي لك و يعطيك ألف عافية،،

1
n622971709_461151_8573.jpg
#5

توجد أيضا htmlparser وهي أفضل لعمل parsing على ملف html، لكن الهدف كان هو معرفة كيفية عمل ذلك بدون مكتبة خارجية وليس النتيجة بحد ذاتها :happy:

#6

أفهم هذا..

لم أرد أكثر من الإفادة :)

تحياتي،

n622971709_461151_8573.jpg
#7

خاصية مفيدة فعلاً ..

و هحاول استغلها فى تطبيق معين ..

-----------------------------------------

لأجل ما تكون الأمرو متضحة :

ال PrserDelegator مسئول عن قراءة صفحة ال Html

ال parsercallback مسئول عن التعرف على ال tags

مش كده ؟؟

شكراً

#8
محمد رياض الخضري كتب:

أفهم هذا..

لم أرد أكثر من الإفادة :)

تحياتي،

أعرف هذا.

نسيت أن أرحب بك. أهلا بك في المنتدى :rose:وان شاء الله تفيد وتستفيد :wub:

mr.beshoy كتب:

ال PrserDelegator مسئول عن قراءة صفحة ال Html

ال parsercallback مسئول عن التعرف على ال tags

مش كده ؟؟

شكراً

الParserDelegator يقوم بعمل parsing للملف html وذلك بالنداء على parser خاص بالhtml

ParserCallback يحتوي على الmethods التي يتم النداء عليها من طرف الparser عند الدخول او الخروج من tag معين

#9

شكراً ياعم عصام .... ربنا يخليك

مواضيع مشابهة