BLOG

Linux Dynamic Scarapper

01/02/2017 tarihinde Fatih AKTOLAN tarafından yazılmıştır.

Django ve Scrapy araçlarının birleştirilmesiyle oluşturulmuş görsel bir crawl aracı. http://django-dynamic-scraper.readthedocs.org/en/latest/index.html




Kurulum ve Gereksinimler


Ana gereksinimler:

1-Python 2.7 (Python 3.x desteklenmiyor)

2-Django 1.4 (Django 1.5 de test edildi,Django 1.6+ desteklenmiyor)

3-Scrapy 0.16 (Scrapy 0.18+ desteklenmiyor)

Zamanlama mekanızmasını kullanmak isterseniz django-celery aracını da yuklemeniz gerekmektedir:

4-django-celery 3.0+ (Celery 3.1 desteklenmiyor)

Resimleri toplamak isterseniz Python resim kütüphanesini yüklemeniz gerekmektedir:

5-Python Image Libray (PIL) 1.1.7+ (Önceki versiyonlar test edilmedi)

Son olarak: DDS veritabanını taşımak için South aracı yardımcı olmaktadır:

6-South 0.7+ (önceki versiyonlar test edilmedi)

Kurulum Adımları:

1- Python kütüphanelerini indirip direk kurabilmek için pip aracını yüklemeliyiz
sudo apt-get install python-pip


2- Ubuntu da tanımlı Scrapy paketleri çok eski olduğu için yeni repo eklemeliyiz
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 627220E7

echo 'deb http://archive.scrapy.org/ubuntu scrapy main' | sudo tee /etc/apt/sources.list.d/scrapy.list

sudo apt-get update && sudo apt-get install scrapy-0.16



3- Scrapy kütüphanelerini pythona eklemeliyiz
pip install Scrapy==0.16

4- Django projesini kurmalıyız
sudo pip install Django==1.5

5- Zamanlama ile farklı tarihlerde web crawl için celery modülünün de yüklememiz gerekiyor.
sudo pip install django-celery==”3.0”

6- Django dynamic scraper ın database migration işlemlerini yapabilmesi için South kütüphanesini kuruyoruz
sudo pip install South

7- Artık Django Dynamic Scraper kurmaya hazırız.
Python kütüphanelerini kurduktan sonra https://github.com/holgerd77/django-dynamic-scraper sayfasından kaynak kodu home dizinine indirilip çalışmaya hazır hale getirilir.
8- scrapy ile kullanmak için sqlite yüklenmesi gerekiyor
sudo apt-get install sqlite
sudo apt-get install sqlite3

9-Eclipse kullanmak için java yüklüyoruz
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer

10-Artık Eclipse kurabiliriz. Wiki içinde eclipse kurulumunu bulabilirsiniz

Django modelleri oluşturma


Modelimizi oluştururken iki tane model sınıfı tanımlamamız gerekiyor. Bunlardan birincisi çekilen datayı kaydeder ikinci ise referans sınıfı olup bunların nerden geldiğini gösterir.
class NewsWebsite(models.Model):
    name = models.CharField(max_length=200)
    url = models.URLField()
    scraper = models.ForeignKey(Scraper, blank=True, null=True, on_delete=models.SET_NULL)
    scraper_runtime = models.ForeignKey(SchedulerRuntime, blank=True, null=True, on_delete=models.SET_NULL)

    def __unicode__(self):
            return self.name


    class Article(models.Model):
    title = models.CharField(max_length=200)
    news_website = models.ForeignKey(NewsWebsite)
    description = models.TextField(blank=True)
    url = models.URLField()
    thumbnail = models.CharField(max_length=200)
    checker_runtime = models.ForeignKey(SchedulerRuntime, blank=True, null=True, on_delete=models.SET_NULL)

    def __unicode__(self):
            return self.title


    class ArticleItem(DjangoItem):
    django_model = Article


@receiver(pre_delete)
    def pre_delete_handler(sender, instance, using, **kwargs):
    if isinstance(instance, NewsWebsite):
            if instance.scraper_runtime:
            instance.scraper_runtime.delete()

    if isinstance(instance, Article):
            if instance.checker_runtime:
            instance.checker_runtime.delete()

    pre_delete.connect(pre_delete_handler)

Yukarda görüldüğü üzere modellere ait field lar tanımlanırken bazılarının tipleri ForeignKey olarak tanımlanmış.Burda sınıfın bu referanslara bağlandığı görünüyor. Bunlar Scraper refaransli olan nasıl scrape edileceği bilgilerini taşır.SchedulerRuntime referenslı olan obje zamanlama bilgilerini kaydeder.
Article sınıfı ise NewsWebsite sınıfına bağlanmış ve başlıkları,açıklamaları,resimleri ve linkleri tutmakta.
Son olarak ArticleItem sınıfında DjangoItem kullanılarak Django veritabanına gelen verinin yazılması sağlanmış.
Sınıfların altında tanımlanan objeler Django Framework den silinirse tam manasıyla başarılı olunmayabilir bu yüzden alta pre_delete_handler metodu tanımlanmış.

Taranacak Nesneleri Tanımlama


İlk önce veritabanını oluşturduğumuzdan emin olmalıyız.
python manage.py syncdb
python manage.py migrate

Artık örnek projemiz çalışmaya hazır
python manage.py runserver

http://127.0.0.1:8000/admin/ sayfasından admin sayfasına girilir.
Admin sayfamıza ulaştıktan sonra ilk olarak scraped obj class sayfasına gidip orda sınıfımızı be objelerini tanımlıyoruz burda dikkat etmemiz gereken nokta modelimizde tanımladığımız sınıf ismiyle ve obje isimleriyle aynı olmalı.Objeleri tanımlarken tiplerini belirtmemiz gerekiyor örneğin standart secersek bulduğu her linki db ye yazar ama standart(update) seçersek çakışan linkleri tekrar yazmaz.
Özellikleri burda tanımlamanın sebebi sonrasında her birine ayrı ayrı xpath atayabilmektir.
Akışdan genel olarak bahsedecek olursak DDS başladığı zaman siteden ana bilgiyi alır ve altındaki özellikleri belirttiğimiz şekilde ayrı ayrı çeker.Ilk olarak objelerimiz tanımlamamız lazım. Tanımlayacığımız özellikler ;base(BASE),title(STANDART),description(STANDART),url(DETAIL_PAGE_URL).

Scraper Tanımlama


Genel scraper yapısını tanımlayacak olursak;
Scraperlar scrpers sayfasından tanımlanmaktadır.Bu sayfaya girerek scrapera yeni bir isim tanımlyıp önceden tanımladığımız scraper objesiye ilişkilendirmemiz gerekiyor.Sayfanın en altnda scrape elemanlarını belirlememiz gerekiyor,önceden tanımladığımız objelerin xpath ve regular expressions değerlerini tanımlayıp elemanlarımız oluşturmuş oluyoruz.Elemanları belirtirken seceneklerden mandatory(zorunlu) seçeneği herzman seçili olmalı değilse veri tabanına kaıt edilmez.Bi örnekle açıklayalım
<td class="kutu">
        <div class="resim">
                <a href="sdasdasdasd">
                        <img alt="sdasda" src="saSASaS">
                </a>
        </div>
        <div class="img_tip">
		</div>
        <span class="title">
                <a href="dsadasdasd">
                        sdasdasdasdasdasda
                </a>
        </span>
</td>

wikinews sitesinden çekeceğimiz ana eleman
<h1 id="makale_baslik" class="makale_baslik">
        asdasdasdasdasd
</h1>

burdaki makale sayfasında çekmek istediğimiz başlık
İlk olarak scraperımaza Haber ismini verelim. Sonrasında tanımladığımız ubje sınıfıyla ilişkilendirelim.
1- Elemanları tanımlarken ana elemanımızı belirtmemiz gerekiyor.Burdaki base eleman wikinews sitesinde makale özetlerinin olduğu “” tagi ve xpathi ise “//td[@class=”l_box”].”
2- Başlığı makale detay sayfasından almak istersek “h1” tagi içinde olduğunu görüyoruz xpath “//h1[@id=”firstHeading”]/span/text()” olur. Burda dikkat edilmesi gereken önemli husus detay sayfasında olduğu için ‘from_detail_page’ kutusunun işaretlenmesi gerekiyor.
3- Diğer standart elemanların base eleaman ile ilişkili olduğunu hatırlatalım description elemanı için xpath “p/span[@class=”l_summary”]/text()” olur ana sayfada olduğu için ‘from_detail_page’ işaretlenmez.
Son olarak url “span[@class=”l_title”]/a/@href” xpathi ile scrape edilir.Ana domainde burda belirtiliyor processor özelliğine “pre_url” textine ise “‘pre_url’:’http://en.wikinews.org‘”
Scraper nesnemizide tanımlamış olduk.
NOT: Scraper tanımlandığında default olarak pause konumunda geliyor bunu aktif konuma geçirmemiz lazım.

Ana Modelimizi Tanımlama


Admin sayfasında NewsWebsite sayfsı açılır ve yeni bir model tanımlanır.Damain siteye tanıtılır. Modelimize isim veririz ve başlanacak anasayfa tanımlanır.Scraper ile eşleştirme yapılır ve scraper runtime 1 olarak tanımlanır.

Scrapy Kurulum


Django modellerimizi oluşturduktan sonra ve scraperı oluşturduktan sonra Scrapy aracını ayarlamamızı gerekiyor. scrapy startproject myscrapyproject komutu ile bir proje oluşturup onu ilişkilendirmek zor olacağiından django projemizi oluşturup bir scrpy.cfg dosyası ekleriz daha rahat hallederiz. Sonuç olarak dizinimiz şöyle olmalı...
example_project/
scrapy.cfg
open_news/
        models.py # Your models.py file
        scraper/
                settings.py
                spiders.py
                (checkers.py)
                pipelines.py
                (tasks.py)
scrapy.cfg dosyamız scraper içindeki settings dosyasına referan sveriyor ve proje adı belirtiliyor.
[settings]
default = open_news.scraper.settings

[deploy]
#url = http://localhost:6800/
project = open_news
ve settings.py dosyası
import os

PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_project.settings") #Changed in DDS v.0.3

BOT_NAME = 'open_news'

SPIDER_MODULES = ['dynamic_scraper.spiders', 'open_news.scraper',]
USER_AGENT = '%s/%s' % (BOT_NAME, '1.0')

ITEM_PIPELINES = [
'dynamic_scraper.pipelines.ValidationPipeline',
'open_news.scraper.pipelines.DjangoWriterPipeline',
]
SPIDER_MODULES ana dizindeki spiderlara ve bizim scraperımıza referrans veriyor.ITEM_PIPELINES ise ana dizindeki pipline lara ve projemizdeki piplena referans oluyor.Burda en az iki tane öz olmalı bunlardan ilki zorunlu olan DDS piplıne diğerleri ise bizim pipline

Spider Sınıfı


Ana proseslerin yapıldığı yerdir.DDS den DjangoSpider sınıfındankalıtım yapılırak üretilmiştir.
from dynamic_scraper.spiders.django_spider import DjangoSpider
    from open_news.models import NewsWebsite, Article, ArticleItem


    class ArticleSpider(DjangoSpider):

name = 'article_spider'

def __init__(self, *args, **kwargs):
    self._set_ref_object(NewsWebsite, **kwargs)
    self.scraper = self.ref_object.scraper
    self.scrape_url = self.ref_object.url
    self.scheduler_runtime = self.ref_object.scraper_runtime
    self.scraped_obj_class = Article
    self.scraped_obj_item_class = ArticleItem
    super(ArticleSpider, self).__init__(self, *args, **kwargs)

Pipline Sınıfı


Scrape edilen nesnelere bazı ekstra özellikler eklemek isteyebiliriz bunun için Pipline sınıfını düzenlememiz gerekir.
    from django.db.utils import IntegrityError
    from scrapy import log
    from scrapy.exceptions import DropItem
    from dynamic_scraper.models import SchedulerRuntime

    class DjangoWriterPipeline(object):

def process_item(self, item, spider):
    try:
        item['news_website'] = spider.ref_object

        checker_rt = SchedulerRuntime(runtime_type='C')
        checker_rt.save()
        item['checker_runtime'] = checker_rt

        item.save()
        spider.action_successful = True
        spider.log("Item saved.", log.INFO)

    except IntegrityError, e:
        spider.log(str(e), log.ERROR)
        raise DropItem("Missing attribute.")

    return item

DDS çalıştırma


Aynı scrayp aracını çalıştırdığımız gibi DDS de termialden çalışır.
scrapy crawl SPIDERNAME -a id=REF_OBJECT_ID
                    [-a do_action=(yes|no) -a run_type=(TASK|SHELL)
                    -a max_items_read={Int} -a max_items_save={Int}]


scrapy crawl article_spider -a id=1 -a do_action=yes
Yanlız burda bazı argumanlar eklenmiştir.
NOT: scrapy çalıştırılırken open_news dizisinin altında olmaya dikkat edilmeli

Fatih AKTOLAN

Bilgisayar Mühendisi

Yorumlar

Henüz yorum yapılmadı. Yorum yapan ilk kişi siz olun

Yorum Yaz