
wxpath - زحف ويب تصريحي باستخدام XPath؛ لغة استعلام ويب (WQL)
جديد: TUI - واجهة طرفية تفاعلية (مدعومة بـ Textual) لاختبار تعبيرات wxpath وتصدير البيانات.

يتطلب Python 3.10+.
pip install wxpath
# لدعم TUI:
pip install "wxpath[tui]"
# تشغيل TUI فورًا عبر uv:
uvx --from "wxpath[tui]" wxpath-tui
wxpath هو زاحف ويب تصريحي حيث يتم التعبير عن الاجتياز مباشرة في XPath. بدلاً من كتابة حلقات زحف أمرية، يتيح لك wxpath وصف ما يجب تتبعه وما يجب استخراجه في تعبير واحد. يقوم wxpath بتنفيذ ذلك التعبير بشكل متزامن، بطريقة عرضية أولى تقريبًا، ويبث النتائج فور اكتشافها.
يقوم هذا التعبير بجلب صفحة، واستخراج الروابط، وبثها بشكل متزامن - بدون الحاجة إلى حلقة زحف:
import wxpath
expr = "url('https://quotes.toscrape.com')//a/@href"
for link in wxpath.wxpath_async_blocking_iter(expr):
print(link)
من خلال إدخال عامل url(...) وبناء ///، يمكن لمحرك wxpath إجراء زحف ويب متكرر (أو مقسم إلى صفحات) واستخراج:
import wxpath
path_expr = """
url('https://quotes.toscrape.com')
///url(//a/@href)
//a/@href
"""
for item in wxpath.wxpath_async_blocking_iter(path_expr, max_depth=1):
print(item)
معظم أدوات كشط الويب تجبرك على كتابة تدفق التحكم في الزحف أولاً، ثم الاستخراج ثانيًا.
wxpath يجمع هاتين الخطوتين في خطوة واحدة:
استخرج تسلسلات هرمية JSON نظيفة ومنظمة مباشرة من الرسم البياني - قم بتغذية نماذج LLM الخاصة بك بالإشارات، وليس بالضوضاء. راجع تكامل LangChain لمزيد من التفاصيل.
wxpath حتمي (أي: لا يعمل بواسطة نماذج LLM). بينما لا يمكننا ضمان استقرار الشبكة، يمكننا ضمان حتمية الاجتياز.
التوثيق متاح الآن هنا.
url(...) و ///url(...)import wxpath
from wxpath.settings import CRAWLER_SETTINGS
# رؤوس مخصصة للتهذيب؛ ضرورية لبعض المواقع (مثل ويكيبيديا)
CRAWLER_SETTINGS.headers = {'User-Agent': 'my-app/0.4.0 (contact: [email protected])'}
# ازحف، استخرج الحقول، ابنِ رسمًا بيانيًا معرفيًا
path_expr = """
url('https://en.wikipedia.org/wiki/Expression_language')
///url(
//main//a/@href[
starts-with(., '/wiki/') and not(contains(., ':'))
]
)
/map{
'title': (//span[contains(@class, "mw-page-title-main")]/text())[1] ! string(.),
'url': string(base-uri(.)),
'short_description': //div[contains(@class, 'shortdescription')]/text() ! string(.),
'forward_links': //div[@id="mw-content-text"]//a/@href ! string(.)
}
"""
for item in wxpath.wxpath_async_blocking_iter(path_expr, max_depth=1):
print(item)
ملاحظة: قد تمنع بعض المواقع (بما في ذلك ويكيبيديا) الطلبات بدون رؤوس مناسبة.
انظر متقدم: تكوين المحرك والزاحف لتعيين User-Agent مخصص.
يقوم التعبير أعلاه بما يلي:
https://en.wikipedia.org/wiki/Expression_language.<main> التي تبدأ بـ /wiki/ ولا تحتوي على نقطتين (:).url(...) و ///url(...)url(...) هو عامل مخصص يقوم بجلب محتوى عنوان URL المحدد من قبل المستخدم أو الذي تم إنشاؤه داخليًا ويعيده ككائن lxml.html.HtmlElement لمزيد من معالجة XPath.///url(...) يشير إلى زحف عميق. يخبر محرك وقت التشغيل بمتابعة تتبع الروابط حتى max_depth المحدد. على عكس القفزات المتكررة url()، يسمح تعبير واحد بوصف استكشاف رسم بياني أعمق. تحذير: استخدم بحذر ومع قيود (عبر max_depth أو مسندات XPath) لتجنب انفجار الاجتياز.انظر DESIGN.md للحصول على تفاصيل تصميم اللغة. سترى المفاهيم الأساسية وتصميم اللغة من الألف إلى الياء.
يقوم wxpath بتقييم تعبير كقائمة من خطوات الاجتياز والاستخراج (يشار إليها داخليًا باسم Segment).
url(...) ينشئ مهام زحف إما بشكل ثابت (عبر عنوان URL ثابت) أو ديناميكيًا (عبر عنوان URL مشتق من تعبير XPath). يتم إزالة تكرار عناوين URL عالميًا، على أساس أفضل جهد - وليس لكل عمق.
تعمل مقاطع XPath على المستندات التي تم جلبها (التي تم جلبها عبر عمليات url(...) السابقة مباشرة).
///url(...) يشير إلى الزحف العميق - يتقدم بطريقة عرضية أولى تقريبًا حتى max_depth.
يتم إرجاع النتائج بمجرد أن تصبح جاهزة.
wxpath يعتمد على asyncio/aiohttp في المقام الأول، ويوفر واجهة برمجة تطبيقات غير متزامنة للزحف واستخراج البيانات.
import asyncio
from wxpath import wxpath_async
items = []
async def main():
path_expr = "url('https://en.wikipedia.org/wiki/Expression_language')///url(//@href[starts-with(., '/wiki/')])//a/@href"
async for item in wxpath_async(path_expr, max_depth=1):
items.append(item)
asyncio.run(main())
يوفر wxpath أيضًا واجهة برمجة تطبيقات غير متزامنة ولكن في سياق متزامن، مما يسمح لك بزحف صفحات متعددة بشكل متزامن مع الحفاظ على بساطة الكود المتزامن. هذا مفيد بشكل خاص للزحف في بيئات تنفيذ متزامنة تمامًا (أي ليس داخل حلقة أحداث asyncio) حيث يكون الأداء مهمًا.
from wxpath import wxpath_async_blocking_iter
path_expr = "url('https://en.wikipedia.org/wiki/Expression_language')///url(//@href[starts-with(., '/wiki/')])//a/@href"
items = list(wxpath_async_blocking_iter(path_expr, max_depth=1))
wxpath يحترم robots.txt افتراضيًا عبر المُنشئ WXPathEngine(..., robotstxt=True).
تقوم واجهة برمجة تطبيقات wxpath في Python بإرجاع كائنات منظمة.
اعتمادًا على التعبير، قد تتضمن النتائج:
lxml.* و lxml.html.*elementpath.datatypes.* (لميزات XPath 3.1)WxStr (قيم نصية مع مصدر)تقوم CLI بتسطير هذه الكائنات إلى JSON عادي للعرض. تحتفظ واجهة برمجة تطبيقات Python بالبنية افتراضيًا.
يستخدم wxpath مكتبة elementpath لتوفير دعم XPath 3.1، مما يتيح ميزات XPath متقدمة مثل الخرائط و المصفوفات وغيرها. يتيح لك هذا كتابة استعلامات XPath أكثر قوة.
path_expr = """
url('https://en.wikipedia.org/wiki/Expression_language')
///url(//div[@id='mw-content-text']//a/@href)
/map{
'title':(//span[contains(@class, "mw-page-title-main")]/text())[1],
'short_description':(//div[contains(@class, "shortdescription")]/text())[1],
'url'://link[@rel='canonical']/@href[1]
}
"""
# [...
# {'title': 'Computer language',
# 'short_description': 'Formal language for communicating with a computer',
# 'url': 'https://en.wikipedia.org/wiki/Computer_language'},
# {'title': 'Machine-readable medium and data',
# 'short_description': 'Medium capable of storing data in a format readable by a machine',
# 'url': 'https://en.wikipedia.org/wiki/Machine-readable_medium_and_data'},
# {'title': 'Domain knowledge',
# 'short_description': 'Specialist knowledge within a specific field',
# 'url': 'https://en.wikipedia.org/wiki/Domain_knowledge'},
# ...]
يوفر wxpath شريط تقدم (عبر tqdm) لتتبع تقدم الزحف. هذا مفيد بشكل خاص للزحفات طويلة المدى.
قم بتمكينه عن طريق تعيين engine.run(..., progress=True)، أو قم بتمرير progress=True إلى أي من دوال wxpath_async*(...).
items = wxpath.wxpath_async_blocking("...", progress=True)
> 100%|██████████████████████████████████████████████████████████▎| 469/471 [00:05<00:00, 72.00it/s, depth=2, yielded=457]
يوفر wxpath واجهة سطر أوامر (CLI) لتجربة وتنفيذ تعبيرات wxpath بسرعة مباشرة من الطرفية.
المثال التالي يوضح كيفية زحف ويكيبيديا بدءًا من صفحة "Expression language"، واستخراج الروابط إلى صفحات ويكي أخرى، واسترداد حقول محددة من كل صفحة مرتبطة.
ملاحظة: نظرًا للطبيعة المتغيرة باستمرار لمحتوى الويب، قد يختلف الإخراج بمرور الوقت.
> wxpath --depth 1 \
--header "User-Agent: my-app/0.1 (contact: [email protected])" \
"url('https://en.wikipedia.org/wiki/Expression_language') \
///url(//div[@id='mw-content-text']//a/@href[starts-with(., '/wiki/') \
and not(matches(@href, '^(?:/wiki/)?(?:Wikipedia|File|Template|Special|Template_talk|Help):'))]) \
/map{ \
'title':(//span[contains(@class, 'mw-page-title-main')]/text())[1], \
'short_description':(//div[contains(@class, 'shortdescription')]/text())[1], \
'url':string(base-uri(.)), \
'backlink':wx:backlink(.), \
'depth':wx:depth(.) \
}"
{"title": "Computer language", "short_description": "Formal language for communicating with a computer", "url": "https://en.wikipedia.org/wiki/Computer_language", "backlink": "https://en.wikipedia.org/wiki/Expression_language", "depth": 1.0}
{"title": "Machine-readable medium and data", "short_description": "Medium capable of storing data in a format readable by a machine", "url": "https://en.wikipedia.org/wiki/Machine_readable", "backlink": "https://en.wikipedia.org/wiki/Expression_language", "depth": 1.0}
{"title": "Domain knowledge", "short_description": "Specialist knowledge within a specific field", "url": "https://en.wikipedia.org/wiki/Domain_knowledge", "backlink": "https://en.wikipedia.org/wiki/Expression_language", "depth": 1.0}
{"title": "Advanced Boolean Expression Language", "short_description": "Hardware description language and software", "url": "https://en.wikipedia.org/wiki/Advanced_Boolean_Expression_Language", "backlink": "https://en.wikipedia.org/wiki/Expression_language", "depth": 1.0}
{"title": "Data Analysis Expressions", "short_description": "Formula and data query language", "url": "https://en.wikipedia.org/wiki/Data_Analysis_Expressions", "backlink": "https://en.wikipedia.org/wiki/Expression_language", "depth": 1.0}
{"title": "Jakarta Expression Language", "short_description": "Computer programming language", "url": "https://en.wikipedia.org/wiki/Jakarta_Expression_Language", "backlink": "https://en.wikipedia.org/wiki/Expression_language", "depth": 1.0}
{"title": "Rights Expression Language", "short_description": [], "url": "https://en.wikipedia.org/wiki/Rights_Expression_Language", "backlink": "https://en.wikipedia.org/wiki/Expression_language", "depth": 1.0}
{"title": "Computer science", "short_description": "Study of computation", "url": "https://en.wikipedia.org/wiki/Computer_science", "backlink": "https://en.wikipedia.org/wiki/Expression_language", "depth": 1.0}
خيارات سطر الأوامر:
--depth <depth> أقصى عمق للزحف
--verbose [true|false] يوفر معلومات CLI سطحية
--debug [true|false] يوفر إخراج تشغيل ومعلومات مفصلة
--concurrency <concurrency> عدد الجلبات المتزامنة
--concurrency-per-host <concurrency> عدد الجلبات المتزامنة لكل مضيف
--header "Key:Value" أضف رأسًا مخصصًا (مثل 'Key:Value'). يمكن استخدامه عدة مرات.
--respect-robots [true|false] (الافتراضي: True) يحترم robots.txt
--cache [true|false] (الافتراضي: False) يستمر حفظ نتائج الزحف في قاعدة بيانات محلية
يوفر wxpath واجهة طرفية (TUI) لاختبار التعبيرات التفاعلية واستخراج البيانات.
انظر بداية سريعة لـ TUI لمزيد من التفاصيل.
wxpath يحفظ اختياريًا نتائج الزحف في قاعدة بيانات محلية. هذا مفيد بشكل خاص عندما تزحف إلى عدد كبير من عناوين URL، وتقرر إيقاف الزحف مؤقتًا، أو تغيير تعبيرات الاستخراج، أو تحتاج إلى إعادة تشغيل الزحف.
يدعم wxpath واجهتين خلفيتين: sqlite و redis. SQLite رائع للزحفات صغيرة النطاق، مع عامل واحد (أي engine.crawler.concurrency == 1). Redis رائع للزحفات واسعة النطاق، مع عدة عمال. ستواجه تحذيرًا إذا كان min(engine.crawler.concurrency, engine.crawler.per_host) > 1 عند استخدام واجهة sqlite الخلفية.
للاستخدام، يجب تثبيت التبعية الاختيارية المناسبة:
pip install wxpath[cache-sqlite]
pip install wxpath[cache-redis]
بمجرد تثبيت التبعية، يجب تمكين التخزين المؤقت:
from wxpath.settings import SETTINGS
# لتمكين التخزين المؤقت؛ sqlite هو الافتراضي
SETTINGS.http.client.cache.enabled = True
# لواجهة redis الخلفية
SETTINGS.http.client.cache.enabled = True
SETTINGS.http.client.cache.backend = "redis"
SETTINGS.http.client.cache.redis.address = "redis://localhost:6379/0"
# تشغيل wxpath كالمعتاد
items = list(wxpath_async_blocking_iter('...', max_depth=1, engine=engine))
انظر settings.py للحصول على تفاصيل الإعدادات.
يدعم wxpath نظام خطافات قابل للتوصيل يسمح لك بتعديل سلوك الزحف والاستخراج. يمكنك تسجيل خطافات لمعالجة عناوين URL مسبقًا، ومعالجة HTML لاحقًا، وتصفية القيم المستخرجة، والمزيد. سيتم تنفيذ الخطافات بالترتيب الذي تم تسجيلها به. قد تؤثر الخطافات على الأداء.
from wxpath import hooks
@hooks.register
class OnlyEnglish:
def post_parse(self, ctx, elem):
lang = elem.xpath('string(/html/@lang)').lower()[:2]
return elem if lang in ("en", "") else None
ملاحظة: قد تكون الخطافات متزامنة أو غير متزامنة، ولكن يجب أن تتبع جميع الخطافات في المشروع نفس النمط. خلط الخطافات المتزامنة وغير المتزامنة غير مدعوم وقد يؤدي إلى سلوك غير متوقع.
from wxpath import hooks
@hooks.register
class OnlyEnglish:
async def post_parse(self, ctx, elem):
lang = elem.xpath('string(/html/@lang)').lower()[:2]
return elem if lang in ("en", "") else None
JSONLWriter (يُعرف أيضًا باسم NDJSONWriter) هو خطاف مدمج يكتب البيانات المستخرجة إلى ملف JSON مفصول بأسطر جديدة. هذا مفيد لتخزين النتائج بتنسيق منظم يمكن معالجته بسهولة لاحقًا.
from wxpath import hooks
hooks.register(hooks.JSONLWriter)
يتطلب Python 3.10+.
pip install wxpath
للحفظ/التخزين المؤقت، يدعم wxpath الواجهات الخلفية التالية:
pip install wxpath[cache-sqlite]
pip install wxpath[cache-redis]
انظر EXAMPLES.md لمزيد من الأمثلة على الاستخدام.
انظر COMPARISONS.md للمقارنات مع أدوات كشط الويب الأخرى.
يمكنك تغيير سلوك المحرك والزاحف كما يلي:
from wxpath import wxpath_async_blocking_iter
from wxpath.core.runtime import WXPathEngine
from wxpath.http.client.crawler import Crawler
crawler = Crawler(
concurrency=8,
per_host=2,
timeout=10,
respect_robots=False,
headers={
"User-Agent": "my-app/0.1.0 (contact: [email protected])", # مواقع مثل ويكيبيديا ستقدر هذا
},
)
# إذا لم يتم تحديد `crawler`، سيتم إنشاء Crawler افتراضي باستخدام
# قيم concurrency و per_host و respect_robots المقدمة، أو بالقيم الافتراضية.
engine = WXPathEngine(
# concurrency: int = 16,
# per_host: int = 8,
# respect_robots: bool = True,
# allowed_response_codes: set[int] = {200},
# allow_redirects: bool = True,
crawler=crawler,
)
path_expr = "url('https://en.wikipedia.org/wiki/Expression_language')//url(//main//a/@href)"
items = list(wxpath_async_blocking_iter(path_expr, max_depth=1, engine=engine))
wxpath_async*)max_depth: int = 1progress: bool = Falseengine: WXPathEngine | None = Noneyield_errors: bool = Falseيمكنك أيضًا استخدام settings.py لتمكين التخزين المؤقت، التحكم في المعدل، التزامن والمزيد.
max_depth.الميزات التالية غير مدعومة بعد:
هذا المشروع في مرحلة التطوير المبكر. المفاهيم الأساسية مستقرة، لكن API والميزات قد تتغير. يرجى الإبلاغ عن المشكلات - خاصة الزحفات الميتة أو السلوك غير المتوقع - وأي ميزات ترغب في رؤيتها (لا يوجد ضمان بتنفيذها).
///) تتطلب انضباط المستخدم لتجنب التوسع غير المحدود (انفجار الاجتياز).max_depth ومسندات وعوامل تصفية XPath للحد من نطاق الزحف.إذا كنت ترغب في المساعدة في بناء أو تشغيل زحافات / خلاصات بيانات باستخدام wxpath (استخراج، جدولة، مراقبة، إصلاح الأعطال) أو احتياجات أخرى لكشط الويب، يرجى الاتصال بي على: [email protected].
إذا أعجبك wxpath وترغب في دعم تطويره، يرجى التفكير في التبرع.
يتبع wxpath semver: <MAJOR>.<MINOR>.<PATCH>.
ومع ذلك، قبل 1.0.0، يتبع 0.<MAJOR>.<MINOR|PATCH>.
AGPL-3.0