منبع اصلی نوشتار زیر در این لینک قرار دارد

چگونه یک روبات جمع آوری اطلاعات از یک سایت بنویسیم؟

در این مقاله قرار است یک روبات بنویسیم که مطالب یک سایت را بخواند و در دیتابیس ذخیره کند ولی چگونه؟

من برای اینکار از چند تا کتابخانه استفاده خواهم کرد.

 

import urllib

site = urllib.urlopen(\'http://www.google.com\')
site_data = site.read()
site.close()

 

در urllib به سادگی می توانید یک آدرس را دانلود کنید. ما برای scrap باید آدرس را بسازیم و هر دفعه دوباره دانلود کنیم.

لایبری بعدی که باید استفاده کنیم lxml است که با آن می توانیم دقیقا element مشخصی را با استفاده از Xpath یا selector از کل html خارج کنیم

 

from lxml import etree, html

content = html.fromstring(site_data)
content.find_class(\"title\")

خوب من یک کد کوچیک می نویسم که کارش اینه که آدرس سایت را بگیرد و هنگام کار بگویید چه کلاسی را می خواهید و در نتایجش که یک دیکشنری است ذخیره کند.

from HTMLParser import HTMLParser
from lxml import etree, html
import urllib

class Stripper(HTMLParser):
   
    def __init__(self):
        self.reset()
        self.fed = []
       
    def handle_data(self, d):
        self.fed.append(d)
       
    def get_data(self):
        return \'\'.join(self.fed)

def strip_tags(html_code):
    s = Stripper()
    s.feed(html_code)
    return s.get_data()

   
class scrap(object):
    \"\"\"
    scrap site with addres and you can access to final_scrap for complete data
    \"\"\"
    final_scrap = dict()
   
    def __init__(self, url=None):
        \"\"\"
        download site
        \"\"\"
        if not url:
            site = open(\'persian.html\', \'r\')
            site.seek(0)
        else:
            site = urllib.urlopen(url)
           
        self.content = site.read()
        self.content = html.fromstring(self.content)
       
    def normalize(self, data):
        striped = etree.tostring(data, encoding=\'utf-8\')
        striped = strip_tags(striped)
        striped = striped.replace(\'\\t\',\'\').replace(\'\\n\',\'\')
        return striped

    def find_and_insert(self, name, element_class, element_number=None):
        \"\"\"
        read self.content and find element_class form html with find_class
        \"\"\"
        scrap_element = self.content.find_class(element_class)
        self.final_scrap[name] = self.normalize(scrap_element[element_number or 0])

خوب حالا من چگونه از این کلاس می تونم استفاده کنم؟

برای این کار من فایل پایتونی scrap رو اجرا می کنم

$ ipython -i scrap.py
Welcome to rlcompleter2 0.96
for nice experiences hit <tab> multiple times
Python 2.6.7 (r267:88850, Aug  3 2011, 11:33:52)
Type \"copyright\", \"credits\" or \"license\" for more information.

IPython 0.10.2 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython\'s features.
%quickref -> Quick reference.
help      -> Python\'s own help system.
object?   -> Details about \'object\'. ?object also works, ?? prints more.

In [1]: a = scrap(\'http://127.0.0.1\')

In [2]: a.find_and_insert(\"title\",\"title\")

In [3]: a.fin
a.final_scrap      a.find_and_insert 

In [3]: a.final_scrap
Out[3]: {\'title\': \'\\xd9\\xbe\\xd8\\xb1\\xd8\\xb4\\xdb\\x8c\\xd9\\x86\'}

In [4]: print a.final_scrap[\'title\']
پرشین

همونطوری که می بینید تونست صفحه رو از localhost من بخونه و نتایج رو درست برگرداند. حالا شما که می خواهید یک مجموعه صفحه را بخوانید و اطلاعاتشان را بدست آورید در یک حلقه آدرس صفحات مختلف را بسازید و اطلاعات مربوطه را که یک دیکشنری است در پایگاه داده خود ذخیره کنید.

به طور مثال من سایتی دارم که آدرسی نظیر http://www.pesarak.ir/?p=320 دارد . همانطور که می بینید ۳۲۰ یک عدد است که با عوض کردنش می توانم به صفحات دیگر دسترسی پیدا کنم. خوب با بررسی بیشتر متوجه می شوم این سایت اخرین صفحه ای که دارد همان ۳۲۰ است پس یک حلقه درست می کنم که از ۱ تا ۳۲۰ برود و یک string که همان آدرس است درست می کنم و به برنامه scrap می دهم و برایم دریافت می کند و در دیتابیس ذخیره می کنم.

دقت کنید احتمال دارد که با گذاشتن اعداد مختلف به صفحه ای برسید که وجود ندارد برای همین بگویید اگر مثلا صفحه مقدار title داشت ذخیره کن وگرنه برو صفحه بعدی ( title فقط مثال است )

روبات شما الان به راحتی می تواند در مدت کوتاهی تمام اطلاعات یک سایت را بدست آورد.

 

موفق باشید