هل يعرف أحد أي زاحف ويب جيد يعتمد على لغة بايثون ويمكنني استخدامه؟

StackOverflow https://stackoverflow.com/questions/419235

  •  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]

الحاصد ، على شبكة الإنترنت، الزاحف متعددة الخيوط مكتوبة في بيثون، وأيضا إعطاء ونتطلع إلى spider.py حدة.

و هنا يمكنك العثور على نماذج التعليمات البرمجية لبناء بسيطة في زاحف الويب ل .

ولقد استعملت 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 ليبني على قائمة ويذهب على الرغم من ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top