Собствен уеб-браузър с PyGTK и WebKit

Автор Владимир Колев | Вариант за отпечатване Вариант за отпечатване   

1 Star2 Stars3 Stars4 Stars5 Stars (не е гласувано)
Loading ... Loading ...
 

PyBrowser - уеб-браузър само в по-малко от 100 реда код

Преглеждайки днес новостите по мрежата в любимия ми сайт TuxRadar попаднах на един нов видео урок, който за 20 минути ни показва как можем да използваме Python, Webkit и PyGTK, за да си направим просто браузър. За съжаление урока не беше пълен и всичкото ставаше от Python интерпретатора, затова реших да използвам видео урока за база и, доколкото е възможно да го разширя до нещо функциониращо. В този урок – ще ви покажа как да създадете от-до браузъра и съответно как да добавите, някои полезни функции. В края на урока ще добавя и препратки, в които можете да търсите повече информация за използването на webkit ако решите да разширите браузъра с повече възможности.

Нека започнем

Какво ще ни бъде необходимо. Първо трябва да се уверите дали имате инсталирано всичко необходимо:

  • python
  • python-gtk2
  • python-webkit

Разбира се, за да пишете код ще ви е необходим и редактор – тук всичко остава във ваши ръце. Ще препоръчам само да не използвате среда за разработка като Eclipse или NetBeans, тъй като за начало е напълно излишно, тъй като ще бъде редактиран само един файл (функционален браузър в един файл – точно така). Разбира се можете да подготвите и три икони – една за прозореца, една за бутон Go и една за презареждане. Може и без тях, но аз не обичам да ползвам бутони с текст. В самия урок, ще добавя коментар, как можете да използвате и нормални бутони с текст или бутоните, включени в GNOME (което ще ви позволи и превод на интерфейса директно с писането на приложението).

Вмъкване на всичко необходимо и първия прозорец

Нека започнем с писането. Първоначално е редно да добавим библиотеките, които ще използваме и да създадем скелета на приложението (класовете и методите). Започваме от вмъкването на необходимите библиотеки със следните 4 реда:

import gtk
# Следващите два реда са необходими, за да не получавате грешка от Glibc при стартирането на приложението
import gobject
gobject.threads_init()
# И разбира се добавяме webkit
import webkit
 
class PyBrowser:
    def __init__(self):
        pass
 
    def main(self):
        # тук стартираме основния метод на gtk
        gtk.main()
 
    def delete_event(self, widget, data=None):
        # тук ще дефинираме изхода от приложението, за което отново използваме метод от gtk
        gtk.main_quit()
 
    def enter_pressed(self, entry):
        # оставяме място за действие при натискате на клавиша Enter в полето за писане
 
    def go_clicked(self, btn):
        # оставяме място да дефинираме действието на бутона Go!
 
    def refresh_browser(self, btn):
        # място за действието на бутона за презареждане на страницата
 
    def title_changed(self, webview, frame, title):
        # добре ще е разбира се да обновяваме заглавието на прозореца със заглавието на настоящата
        # страница
 
if __name__ == "__main__":
    # След като използваме класове трябва да ги прехвърлим към обект
    browse = PyBrowser()
    # и с този обект да извикаме основния метод main()
    browse.main()

Както виждате основната част на приложението е изключително интуитивна. Редно е да се поясни, че конструктора __init__ ще ни служи за да построим самия прозорец на приложението и в него ще опишем всички действия, бутони, полета и самия браузър. Ако до момента не сте срещали подобен конструктор прегледайте http://www.penzilla.net/tutorials/python/classes/ – изключително добре описано с примери .Също така self обяснява, че това са лични методи към класът PyBrowser и за да ги извикваме ще трябва да пишем self пред името на всеки метод.

Да създадем прозореца с джаджите

В gtk всяко нещо е widget, включително бутоните, полетата за текст и т.н. И те трябва да бъдат добавяни в съдържатели – било то фиксирани, вертикални кутии, хоризонтални кутии, таблици и т.н. В този урок ние ще използваме вертикални и хоризонтални кутии. Но преди това нека първо създадем нашия прозорец. Това става изключително лесно добавяме следното в __init__:

        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.connect("delete_event", self.delete_event)
        self.window.set_title("PyBrowser v.0.1")
        self.window.set_icon_from_file("icons/pybrowser_small.png")
        self.window.resize(600, 480)

Да поясним какво сме направили – с първия ред създаваме нов прозорец, който да бъде първи в йерархията (в случай, че по-късно използваме още прозорци към приложението). Свързваме “delete_event” – с методът, който предварително сме дефинирали. Това е важно, за да кажем на нашето приложение, че при натискане на бутона X в заглавната лента на прозореца искаме приложението да спира да работи. След което с set_title, set_icon_from_file и resize определяме какво да бъде заглавието на нашето приложение, къде се намира иконата на прозореца (директорията icons/ трябва да се намира при файла pybrowser.py) и определяме големината на прозореца по подразбиране 600×480 пиксела.

Време е да дефинираме и нашите съдържатели – ще използваме три: HBox, VBox и ScrolledWindow. Последният ще съдържа нашият браузър, за да можем при отварянето на страници, по-големи от нашият прозорец да използваме плъзгачи за скрол. С други думи добавяме следното:

        # контейнерът за webkit
        self.scroller = gtk.ScrolledWindow()
        # hbox и vbox сътоветно за хоризонтална и вертикална подредба
        self.vbox = gtk.VBox()
        self.hbox = gtk.HBox()

Няма никакво значение как ще ги подредите, тъй като самото им използване ще се случи малко по-надолу в кода. HBox ще използваме за текстовото поле, в което ще въвеждаме URL, бутонът за старт на зареждането и бутонът за презареждане. Остава да ги дефинираме и да ги добавим към съдържателя:
Първо да създадем нашето текстово поле:

        # Дефинираме нашето поле с името urltext
        self.urltext = gtk.Entry()
        # Задаваме на полето текст по подразбиране - не е задължително
        # но пък от друга страна е по-добре от празна кутия
        self.urltext.set_text("http://")
        # задаваме размер по подразбиране - първата стойност ще бъде пропусната по подразбиране
        # докато втората, ще се използва за задаване на височината, тъй като бутоните, които аз
        # използвам са с рамери 32x32. В случай, че използвате други размери, можете спокойно
        # да изтриете този ред
        self.urltext.set_size_request(600,38)
        # Свързваме действие, когато потребителя въведе адрес и натисне клавиша Enter
        # нещо, което повечето хора правят дори несъзнателно
        self.urltext.connect("activate", self.enter_pressed)

След като имаме полето за текст остава да създадем и двата бутона:

        # Създаваме нов бутон с името gobutton
        # В случай, че решите да не използвате изображение, можете да изтриете
        # следните 3 реда и да промените този на:
        #self.gobutton = gtk.Button("Go!")
        self.gobutton = gtk.Button()
        # Дефинираме обект за изображение goimage, в който ще запишем
        # изображението, което ще използваме за този бутон
        self.goimage = gtk.Image()
        # задаваме пътят към изображението
        self.goimage.set_from_file("icons/go.png")
        # прикачаме изображението към бутона
        self.gobutton.set_image(self.goimage)
        # Ако сте решили да не използвате изображения, тук трябва да спрете с триенето
        # Задаваме действие не бутона, когато той бъде натиснат искаме да се изпълни
        # методът go_clicked
        self.gobutton.connect("clicked", self.go_clicked) # the Go! button
 
        # Правим същото за бутонът за презареждане
        self.refresh = gtk.Button()
        self.refreshimage = gtk.Image()
        self.refreshimage.set_from_file("icons/reload.png")
        self.refresh.set_image(self.refreshimage)
        self.refresh.connect("clicked", self.refresh_browser) # The reload button
 
        # След като сме създали текстовото поле и бутоните трябва
        # да ги добавим към хоризонталния съдържател HBox
        self.hbox.pack_start(self.urltext)
        # Забележете вторият параметър False, той казва на Gtk
        # Че тези бутони трябва да използват минималното място,
        # от което се нуждаят за да бъдат показани
        self.hbox.pack_start(self.gobutton, False)
        self.hbox.pack_start(self.refresh, False)

Нека създадем и нашият браузър:

        # Дефинираме браузъра си като WebView - рамка за визуализиране
        # на HTML страници
        self.browser = webkit.WebView()
        # Просто защото е забавно задаваме още тук браузърът да отвори google
        # По този начин си имаме първоначална страница за зареждане
        # Ако искате да използвате файл, можете да добавите следното, като
        # предварително добавите import os при вмъкването на библиотеките:
        # self.browser.open("file://%s/file.html" % (os.getcwd()))
        self.browser.open("http://www.google.com/webhp?hl=en")
        # Използваме слушател, който да стартира метода title_changed, щом
        # заглавието на страницата бъде променено
        self.browser.connect("title-changed", self.title_changed)
        # Създаваме сигнал, който ще контролира нашата лента за зареждане
        # по този начин "слушаме" за промени
        self.browser.connect("load-progress-changed", self.load_progress_changed)
        # дефинираме какво трябва да се случи при започване на зареждане
        self.browser.connect("load-started", self.load_started)
        # дефинираме и какво трябва да се случи, когато страницата е заредена
        # тези методи ще създадем след малко
        self.browser.connect("load-finished", self.load_finished)
        # Добавяме, както споменахме по-рано браузърът в ScrolledWindow съдържател
        # така можем да използваме плъзгачи, в случай, че страницата е по-голяма
        # от нашия прозорец
        self.scroller.add(self.browser)

В следващата част от нашият код, ще извършим няколко неща наведнъж, а именно:
1. Ще създадем нашата лента за прогрес

        self.progress = gtk.ProgressBar()

2. Ще добавиме всичките до сега дефинирани джаджи във вертикалния съдържател, като не трябва да забравяте, че този тип съдържатели, могат да съдържат и други съдържатели:

        # Първо добавяме нашата хоризонтална кутия, с текстовото поле
        # и бутоните. Помните вторият параметър (Flase), оказва съответната
        # джаджа да не се разпростира много, а да използва от прозореца
        # само толкова, колкото й трябва
        self.vbox.pack_start(self.hbox, False)
        # Под бутоните и текстовото поле бихме искали директно да виждаме
        # нашият браузър
        self.vbox.pack_start(self.scroller)
        # И накрая добавяме лентата за прогрес, която по-късно ще скрием
        self.vbox.pack_start(self.progress, False)

3. Последното, което остана при дефинирането на нашия прозорец е той да съдържа дефинираните до сега съдържатели и да бъде показан. Това правим по следния начин:

        # Vbox вече съдържа всичките джаджи, които сме дефинирали
        self.window.add(self.vbox)
        # Казваме на нашият прозорец да покаже всичко, което сме му добавили,
        # включително и себе си
        self.window.show_all() # Just show everything

Малко действия

До тук това, което постигнахме е просто един прозорец, който в идеалния случай ще се зареди, но няма да бъде функционален, тъй като бутоните, и самите действия все още не са дефинирани. Прегледайте отново скелета на приложението. Ще разгледаме методите един по един. Като накрая ще добавим методите, който ще контролират нашата лента за прогрес (не мога да измисля по-точен превод на български, така че моля уважаемият читател да ме извини).

Натискането на клавишът [Enter]:

def enter_pressed(self, entry):
        self.browser.open(self.urltext.get_text())

Методът приема два параметъра – първо, че е част от класа, второто, че сигналът му е пратен от Entry – текстово поле. Това което казваме да се случи: нека браузърът (self.browser) отвори (open) съдържанието на текстовото поле. self.urltext – е нашето текстово поле и то има метод get_text(), който взима неговото съдържание. В Този метод можете да добавите и проверка, дали въведения адрес е валиден или пък ако искате при невалиден адрес, да отворите google търсачката. За целта нека ви покажа как можете да го направите по по-елементарния начин (без регулярни изрази):

def enter_pressed(self, entry):
    # съдържанието на текстово поле го записваме в променлива
    theurl = self.urltext.get_text()
    # и започваме да проверяваме:
    if "http://" in theurl or "www." in theurl:
        self.browser.open(theurl)
    else:
        # Ако няма http или www в адреса, допускаме, че това е
        # просто някакъв текст, за да го превърнем в текст, който
        # да добавим към адреса на google за търсене заменяме празните
        # полета със знака +
        searchterm = theurl.replace(" ", "+")
        # предаваме нов адрес, в който е и нашето понятие за търсене
        self.browser.open("http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=%s" % searchterm)

Идентичен е и метода при натискането на бутона Go!. Разликата е в това, че сигналът се изпраща от бутон:

def go_clicked(self, btn):
    self.browser.open(self.urltext.get_text())

По същия начин описан по-горе, можете да си добавите и проверка. Би било добре тази проверка да я направите с регулярен израз, защото ще е по-смислено и по-практично.

Методът за нашият бутон за презареждане ще изглежда по следния начин:

def refresh_browser(self, btn):
    # За наше успокоение WebView от WebKit има тази функция вградена
    # и това, което трябва да направим е просто да я извикаме
    self.browser.reload()

Разбрахме се още в началото, че нашият браузър ще показва заглавието на настоящата страница – затова и добавихме сигнал при дефинирането на нашият браузър, това, което остава за нас е да кажем какво трябва да се случи.

def title_changed(self, webview, frame, title):
     # Тук това вече е част от нашият Gtk прозорец, затова и не извикваме
     # webkit на помощ, от него просто взимаме заглавието
    self.window.set_title(title)

Малкото, което остана е да дефинираме и три метода за нашата прогресна лента. Единият от тях трябва да разделя зареждането на стъпки. Другите два служат просто за прихващане на сигналите – “започване на зареждането” и “приключване на зареждането”. WebKit ни улеснява изключително много и в трите метода. Като ни предлага всичко готово. Това, което се изисква от нас е да определим как ще бъдат разделени стъпките, за да ги разбере GTK и какво трявбад а се случва при започване на зареждане и когато страницата бъде заредена.

    def load_progress_changed(self, webview, amount):
        # Тук ще обясня какво е amount - това е цялото количество данни, които
        # ще бъдат изтеглени - това ни се подава от WebKit. За да работи
        # Нашата прогресна лента - трябва големината на данните, да разделим на 100.0
        # Нарочно не използваме integer - остава да подадем резултата на метода
        # set_fraction, който е част от gtk.ProgressBar
        self.progress.set_fraction(amount / 100.0)
 
    def load_started(self, webview, frame):
        # За да бъде по-интерактивен браузъра показваме
        # лентата за зарежда само, когато има зареждане
        self.progress.show()
 
    def load_finished(self, webview, frame):
        # Щом зареждането приключи взимаме адреса на заредената
        # страница и го записваме в текстовото поле за адрес
        # след което скриваме лентата за зареждане, за да не ни пречи
        self.urltext.set_text(frame.get_uri())
        self.progress.hide()

Край

Надявам се с този урок да сте разбрали колко е лесно да направите собствен браузър с Python и WebKit. Това, което можете да приемете като домашно е да разгледате другите методи, и действия, които ви предлага Webkit и просто да ги добавите във вашето приложение. Тъй като за момента не успях да намеря публично API, с python-webkit аз използвах това, което е за C – не се различават по нищо, тъй като ако не знаете, Python почти без проблем използва WebKitWebView С-библиотеките като собствени.

Разбира се можете да изтеглите и крайният резултат в случай, че имате проблем с разбирането на целия текст.
PyBrowse (13.08 KB) 125 изтегляния

Относно автора

Владимир Колев е написал 48 статии в този блог.

Студент в техническия университет в град Кьолн/Германия. Занимава се с програмиране от 6 години. Предпочитан език за програмиране Python. Други езици: C, Java, PHP, MySQL, SQLite.


Вашите коментари

2 Коментара

  1. Николай
    Posted 31/05/2010 at 07:17 | Permalink | Reply

    Първа да кажа едно искрено благодаря за интерсния урок, а след това една малка забележка, линка за WebKitWebView С-библиотеките не работи, поне при мен.

    Поздрави Николай.

Публикувай коментар

Вашият е-мейл никога няма да бъде споделен. Задължителните полета са маркирани с *

*
*

Switch to our mobile site