Scrapy İle Arama Motoru

Bloglar ve siteler olduğundan beri bir siteden diğerine veri çekmek her zaman programcılar için onemli oldu. Kimi zaman sitelerin webmasterlar için verdiği araçları kullandık kimi zaman da kendimiz yazmak zorunda kaldık. Tabi zaman ilerleryince arama motoru tarafında da gelişmeler hızla ilerledi. Ciddi derece iyi motorlar ve botlar yazıldı. Ben PHP ile yazdığım sitemi Python ile yazdığım şu anki haline taşırken kesinlikle MySql to PostgreSql veya benzeri yazılımlar kullanmadım. Çunku PHP blogumda herşey karşık ve dağınıktı.

Şimdi ise Django bir hayli duzenli. Bu yuzden donuşturmek yerine direk olarak sayfadan verileri almam gerektiği duşundum. Boylece en başta bahsettiğim botlar dunyasına bakmam gerekti. Ben bu botlardan zamanında pek de haberdar değildim. Bu yuzden Python ile birkaç spagetti kod ile urllib, urllib2 ve for, while dongulerini kullanarak tum yazılarımı etiketlerimi çektim.

Ama aklıda hep bu işi profesyonel olarak yazılmış bir botla yapmak vardı. Biraz araştırınca Python ile ScraPy adında harika bir arama motoru ile karşılaştım. Bununla takip etmesini istediğim sayfaları regex ile belirtip aynı şekilde veri almasını istediklerimi de ayrı ayrı belirtiyoruz.

Öncelikle ScraPy'yi bi bilgisayarımıza kuralım.Bunun için klasik olarak aşağıdaki komutu kullanıyoruz.

pip install scrapy

Daha sonra sanal ortamımızda aşağıdaki komut ile klasorlerimiz oluşturuyoruz.

scrapy startproject orumcek

Bu komutu verdiğimizde aşağıdaki gorunumde bir dizin elde etmeniz gerekli.

orumcek/
    scrapy.cfg
    orumcek/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py

Bu dosyaların gorevlerine bakacak olursak:

  • scrapy.cfg: ayar dosyamız
  • orumcek/: proje klasorumuz
  • orumcek/items.py: projemize ait oğeler burada
  • orumcek/pipelines.py: projemizdeki verileri bu dosya sayesinde paylaştıracağız
  • orumcek/settings.py: projemize ait ayarlar
  • orumcek/spiders/: orumceklerimiz bu klasor altında yer alacak

Şimdi herşeyimiz hazır olduğuna gore ilk kodlarımızı yazabiliriz.Öncelikle bize gerekli olan kısımları soyleyim. items.py içinde hangi verileri çekeceğimizi tanımlayacağız. Benim tanımladığım ornek dosya aşağıda.

from scrapy.item import Item, Field

class OrumcekItem(Item):
    title       = Field()
    description = Field()
    #post        = Field()
    date        = Field()

Bu dosyanının gorevini anlamış olmalısınız.Çekeceğimiz verilerin title, description ve date olacağını tanımlıyoruz.(Şimdilik post'u çekmiyorum. Eğer başındaki # işaretini kaldırırsanız onu da çekebilirsiniz. Ancak çok fazla kargaşa yarattığı için şimdilik gerek yok. Siz isteğinize gore ekleyebilirsiniz.)

Şimdi de onemli kısma gelelim. Burada orumceğimizi yazacağız. Bunun için oncelikle spiders/ klasorunun altına bir python dosyası oluşturuyoruz. Ben ismini hd_spider.py koydum. Ve içeriğini aşağıdaki gibi yapıyoruz.

from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.selector import HtmlXPathSelector
from orumcek.items import OrumcekItem


class OrumcekSpider(CrawlSpider):
    name = 'orumcek'
    start_urls = ['http://www.halitalptekin.com/blog/']
    rules = [Rule(SgmlLinkExtractor(allow=[r'\?page=\d+']), follow=True),
             Rule(SgmlLinkExtractor(allow=[r'\w+.html']), callback='parse_blogpost')]

    def parse_blog(self, response):
        hxs = HtmlXPathSelector(response)
        item = OrumcekItem()

        item['title']       = hxs.select("//div[@class='span9']/h1/a/text()").extract()
        item['description'] = hxs.select("//div[@class='span9']/p[@class='lead']/text()").extract()
        item['date']        = hxs.select("//div[@class='span9']/h1/small/text()").extract()
        #item['post']        = hxs.select("//div[@class='span9']/p/text()").extract()
        return item

Kodumuzda ilk olarak isim ve taramanın başlanacağı linki ekliyoruz. Bu link başlangıç noktası olarak alınacak ve daha sonra gelen kurallara gore takip edilecek. Kurallar içinde regex kullandığımı gorebilirsiniz. Burada dikkat etmeniz gereken nokta eğer takip etmesini istediğin linkler varsa bunlara follow=True kuralını ekliyoruz. Veri çekmesini istediklerimizde de o sayfayı parse edecek fonksiyonumuzu çağırıyoruz.

Yukarıdaki kodun Turkçesi; http://www.halitalptekin.com/blog/ linkine gir ve ?page=sayi olan tum sayfalarda gez(?page=1, ?page=2) .Eğer içlerinde \w+.html kuralına uyan(sonu .html ile biten) sayfalar varsa bunları parse_blog fonksiyonuna gonder.

parse_blog fonksiyonuna gelen sayfalarda da oğelerimizi xpath kurallarına gore çekiyoruz. Mesela ben item isimli oğemizin span9 ve sırayla h1, a etiketleri altındaki metin olduğunu belirtmişim.Burada sizin xpath bilginizi konuşturmanız gerekli.Zaten çok da zor bir durum yok.

Bundan sonra aşağıdaki komutu çalıştırarak deneme yapabilirsiniz. Gelen değerler istediğiniz şekilde değilse duzeltmeleri kendinize gore yapın.

scrapy crawl orumcek

Ve şimdi de bu aldığımız verileri bir çıktı haline getirelim. Siz isterseniz xml, feed, json, txt veya direk veritabanına ekleme yapabilirsiniz. Ben json olarak çıktı alacağım. Bunun için pipelines.py dosyamıza aşağıdaki satırları ekliyoruz.

import json

class JsonWriterPipeline(object):

    def __init__(self):
        self.file = open('items.json', 'wb')

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item

Bu kod ile gelen itemleri json dosyamıza serialize ediyoruz. Siz isterseniz bu kısımda bilginizi konuşturarak verileri mongodb, mysql veya xml şeklinde de alabilirsiniz. Burada yapmanız gerekenler sitesinde ayrıntılı anlatılmış.

Daha sonra bu boru hattımızı ayar dosyamıza ekliyoruz. Bunun için settings.py içine aşağıdaki satırı ekliyoruz.

ITEM_PIPELINES = ['orumcek.pipelines.JsonWriterPipeline',]

Artık herşey hazır. Gene yukarıdaki komutuzu girerek aynı dizinde json dosyamızın oluştuğunu gorebilirsiniz.

Python Web Crawler Spider

Ben verileri alırken direk olarak yazılarımı çekmedim. Bunun sebebi Turkçe karakterlerin ascii olarak gelmesi. Bunun çozumu bir hayli basit ancak gene de goz karmaşasına yol açıyor. Github depoma koyduğum json dosyama bakarak ascii karakterleri gayet guzel donuşturduğumu gorebilirsiniz.

comments powered by Disqus