هل يعرف أحد أي زاحف ويب جيد يعتمد على لغة بايثون ويمكنني استخدامه؟
-
03-07-2019 - |
سؤال
أشعر بالرغبة في الكتابة بنفسي، لكن ليس لدي الوقت الكافي حقًا الآن.لقد رأيت قائمة ويكيبيديا من برامج الزحف مفتوحة المصدر لكنني أفضل شيئًا مكتوبًا بلغة بايثون.أدرك أنه ربما يمكنني فقط استخدام إحدى الأدوات الموجودة على صفحة ويكيبيديا وتغليفها بلغة بايثون.قد ينتهي بي الأمر بفعل ذلك - إذا كان لدى أي شخص أي نصيحة حول أي من هذه الأدوات، فأنا منفتح لسماع عنها.لقد استخدمت Heritrix عبر واجهة الويب الخاصة بها ووجدتها مرهقة للغاية.بالتأكيد لن أستخدم واجهة برمجة تطبيقات المتصفح لمشروعي القادم.
شكرا لك مقدما.أيضًا، هذا هو سؤالي الأول في SO!
المحلول
- ميكنة هو المفضل لدي.إمكانات تصفح رائعة عالية المستوى (ملء النماذج وإرسالها بشكل بسيط للغاية).
- نسيج قطني طويل هي لغة برمجة بسيطة مبنية على Mechanize
- حساء جميل + urllib2 يعمل أيضًا بشكل جيد جدًا.
- سكرابي يبدو وكأنه مشروع واعد للغاية؛إنها جديدة.
نصائح أخرى
يستخدم سكرابي.
إنه إطار عمل لزاحف الويب الملتوي.لا يزال قيد التطوير المكثف ولكنه يعمل بالفعل.لديه العديد من الأشياء الجيدة:
- دعم مدمج لتحليل HTML وXML وCSV وJavascript
- مسار وسائط لاستخراج العناصر التي تحتوي على صور (أو أي وسائط أخرى) وتنزيل ملفات الصور أيضًا
- دعم لتوسيع Scrapy عن طريق توصيل الوظائف الخاصة بك باستخدام البرامج الوسيطة والإضافات وخطوط الأنابيب
- مجموعة واسعة من البرامج الوسيطة والإضافات المضمنة للتعامل مع الضغط وذاكرة التخزين المؤقت وملفات تعريف الارتباط والمصادقة وانتحال وكيل المستخدم ومعالجة ملف robots.txt والإحصائيات وتقييد عمق الزحف وما إلى ذلك
- وحدة تحكم القشط التفاعلية، مفيدة جدًا للتطوير وتصحيح الأخطاء
- وحدة تحكم لإدارة الويب لمراقبة الروبوت الخاص بك والتحكم فيه
- وحدة تحكم Telnet للوصول على مستوى منخفض إلى عملية Scrapy
مثال على الكود لاستخراج معلومات حول جميع ملفات التورنت المضافة اليوم في ملف mininova تم إرجاع موقع تورنت، باستخدام محدد XPath على HTML:
class Torrent(ScrapedItem):
pass
class MininovaSpider(CrawlSpider):
domain_name = 'mininova.org'
start_urls = ['http://www.mininova.org/today']
rules = [Rule(RegexLinkExtractor(allow=['/tor/\d+']), 'parse_torrent')]
def parse_torrent(self, response):
x = HtmlXPathSelector(response)
torrent = Torrent()
torrent.url = response.url
torrent.name = x.x("//h1/text()").extract()
torrent.description = x.x("//div[@id='description']").extract()
torrent.size = x.x("//div[@id='info-left']/p[2]/text()[2]").extract()
return [torrent]
ولقد استعملت Ruya و منهم أنه كان جيدا جدا.
وأنا اخترق النصي أعلاه إلى تضمين صفحة تسجيل الدخول وأنا الحاجة إليها للوصول إلى موقع دروبال. ليست جميلة ولكن قد تساعد شخص هناك.
#!/usr/bin/python
import httplib2
import urllib
import urllib2
from cookielib import CookieJar
import sys
import re
from HTMLParser import HTMLParser
class miniHTMLParser( HTMLParser ):
viewedQueue = []
instQueue = []
headers = {}
opener = ""
def get_next_link( self ):
if self.instQueue == []:
return ''
else:
return self.instQueue.pop(0)
def gethtmlfile( self, site, page ):
try:
url = 'http://'+site+''+page
response = self.opener.open(url)
return response.read()
except Exception, err:
print " Error retrieving: "+page
sys.stderr.write('ERROR: %s\n' % str(err))
return ""
return resppage
def loginSite( self, site_url ):
try:
cj = CookieJar()
self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
url = 'http://'+site_url
params = {'name': 'customer_admin', 'pass': 'customer_admin123', 'opt': 'Log in', 'form_build_id': 'form-3560fb42948a06b01d063de48aa216ab', 'form_id':'user_login_block'}
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
self.headers = { 'User-Agent' : user_agent }
data = urllib.urlencode(params)
response = self.opener.open(url, data)
print "Logged in"
return response.read()
except Exception, err:
print " Error logging in"
sys.stderr.write('ERROR: %s\n' % str(err))
return 1
def handle_starttag( self, tag, attrs ):
if tag == 'a':
newstr = str(attrs[0][1])
print newstr
if re.search('http', newstr) == None:
if re.search('mailto', newstr) == None:
if re.search('#', newstr) == None:
if (newstr in self.viewedQueue) == False:
print " adding", newstr
self.instQueue.append( newstr )
self.viewedQueue.append( newstr )
else:
print " ignoring", newstr
else:
print " ignoring", newstr
else:
print " ignoring", newstr
def main():
if len(sys.argv)!=3:
print "usage is ./minispider.py site link"
sys.exit(2)
mySpider = miniHTMLParser()
site = sys.argv[1]
link = sys.argv[2]
url_login_link = site+"/node?destination=node"
print "\nLogging in", url_login_link
x = mySpider.loginSite( url_login_link )
while link != '':
print "\nChecking link ", link
# Get the file from the site and link
retfile = mySpider.gethtmlfile( site, link )
# Feed the file into the HTML parser
mySpider.feed(retfile)
# Search the retfile here
# Get the next link in level traversal order
link = mySpider.get_next_link()
mySpider.close()
print "\ndone\n"
if __name__ == "__main__":
main()
صدقني لا يوجد أفضل من التجعيد...يمكن للكود التالي الزحف إلى 10000 عنوان URL بالتوازي في أقل من 300 ثانية على Amazon EC2
حذر: لا تصل إلى نفس المجال بهذه السرعة العالية...
#! /usr/bin/env python
# -*- coding: iso-8859-1 -*-
# vi:ts=4:et
# $Id: retriever-multi.py,v 1.29 2005/07/28 11:04:13 mfx Exp $
#
# Usage: python retriever-multi.py <file with URLs to fetch> [<# of
# concurrent connections>]
#
import sys
import pycurl
# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
import signal
from signal import SIGPIPE, SIG_IGN
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
except ImportError:
pass
# Get args
num_conn = 10
try:
if sys.argv[1] == "-":
urls = sys.stdin.readlines()
else:
urls = open(sys.argv[1]).readlines()
if len(sys.argv) >= 3:
num_conn = int(sys.argv[2])
except:
print "Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0]
raise SystemExit
# Make a queue with (url, filename) tuples
queue = []
for url in urls:
url = url.strip()
if not url or url[0] == "#":
continue
filename = "doc_%03d.dat" % (len(queue) + 1)
queue.append((url, filename))
# Check args
assert queue, "no URLs given"
num_urls = len(queue)
num_conn = min(num_conn, num_urls)
assert 1 <= num_conn <= 10000, "invalid number of concurrent connections"
print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
print "----- Getting", num_urls, "URLs using", num_conn, "connections -----"
# Pre-allocate a list of curl objects
m = pycurl.CurlMulti()
m.handles = []
for i in range(num_conn):
c = pycurl.Curl()
c.fp = None
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.setopt(pycurl.MAXREDIRS, 5)
c.setopt(pycurl.CONNECTTIMEOUT, 30)
c.setopt(pycurl.TIMEOUT, 300)
c.setopt(pycurl.NOSIGNAL, 1)
m.handles.append(c)
# Main loop
freelist = m.handles[:]
num_processed = 0
while num_processed < num_urls:
# If there is an url to process and a free curl object, add to multi stack
while queue and freelist:
url, filename = queue.pop(0)
c = freelist.pop()
c.fp = open(filename, "wb")
c.setopt(pycurl.URL, url)
c.setopt(pycurl.WRITEDATA, c.fp)
m.add_handle(c)
# store some info
c.filename = filename
c.url = url
# Run the internal curl state machine for the multi stack
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
# Check for curl objects which have terminated, and add them to the freelist
while 1:
num_q, ok_list, err_list = m.info_read()
for c in ok_list:
c.fp.close()
c.fp = None
m.remove_handle(c)
print "Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL)
freelist.append(c)
for c, errno, errmsg in err_list:
c.fp.close()
c.fp = None
m.remove_handle(c)
print "Failed: ", c.filename, c.url, errno, errmsg
freelist.append(c)
num_processed = num_processed + len(ok_list) + len(err_list)
if num_q == 0:
break
# Currently no more I/O is pending, could do something in the meantime
# (display a progress bar, etc.).
# We just call select() to sleep until some more data is available.
m.select(1.0)
# Cleanup
for c in m.handles:
if c.fp is not None:
c.fp.close()
c.fp = None
c.close()
m.close()
بسيطة العنكبوت يستخدم BeautifulSoup وurllib2. شيء متطور جدا، يقرأ فقط كل من أ href ليبني على قائمة ويذهب على الرغم من ذلك.