2009-04-28 3 views
2

Хотя я играл с python в течение нескольких месяцев (просто любитель), я очень мало знаю о веб-программировании (немного html, нулевой javascript, и т.д). Тем не менее, у меня есть текущий проект, который заставляет меня смотреть на веб-программирование в первый раз. Это заставило меня спросить:Python html output (первая попытка), несколько вопросов (включая код)

What's easiest way to get Python script output on the web?

Thx к ответам, я сделал некоторые успехи. Пока что я просто использую python и html. Я не могу опубликовать код проекта, поэтому я написал небольшой пример, используя твиттер-поиск (см. Ниже).

Мои вопросы:

(1) я делаю что-нибудь ужасно глупое? Я чувствую, что WebOutput() понятен, но неэффективен. Если я использовал javascript, я предполагаю, что могу написать файл шаблона html, а затем просто обновить данные. да? лучший способ сделать это?

(2), в какой момент была бы подходящей для приложения подходящая структура? Overkill?

Извините за основные вопросы - но я не хочу тратить слишком много времени на неправильный путь.

import simplejson, urllib, time 

#query, results per page 
query = "swineflu" 
rpp = 25 
jsonURL = "http://search.twitter.com/search.json?q=" + query + "&rpp=" + str(rpp) 

#currently storing all search results, really only need most recent but want the data avail for other stuff 
data = [] 

#iterate over search results 
def SearchResults(): 
    jsonResults = simplejson.load(urllib.urlopen(jsonURL)) 
    for tweet in jsonResults["results"]: 
     try: 
      #terminal output 
      feed = tweet["from_user"] + " | " + tweet["text"] 
      print feed 
      data.append(feed) 
     except: 
      print "exception??" 

# writes latest tweets to file/web 
def WebOutput(): 
    f = open("outw.html", "w") 
    f.write("<html>\n") 
    f.write("<title>python newb's twitter search</title>\n") 
    f.write("<head><meta http-equiv='refresh' content='60'></head>\n") 
    f.write("<body>\n") 
    f.write("<h1 style='font-size:150%'>Python Newb's Twitter Search</h1>") 
    f.write("<h2 style='font-size:125%'>Searching Twitter for: " + query + "</h2>\n") 
    f.write("<h2 style='font-size:125%'>" + time.ctime() + " (updates every 60 seconds)</h2>\n") 

    for i in range(1,rpp): 
     try: 
      f.write("<p style='font-size:90%'>" + data[-i] + "</p>\n") 
     except: 
      continue 

    f.write("</body>\n") 
    f.write("</html>\n") 
    f.close() 

while True: 
    print "" 
    print "\nSearching Twitter for: " + query + " | current date/time is: " + time.ctime() 
    print "" 
    SearchResults() 
    WebOutput() 
    time.sleep(60) 
+1

Thx all (llimllib, THC4k, dbr, Buddy)! Я определенно вижу ценность использования фреймворка даже для небольшого проекта. Я рассмотрю различные варианты и посмотрю, какой из них мне больше всего нравится. llimllib: Благодарю вас за очень ясный пример. это было очень полезно! dbr: большой thx !! чем ожидалось. (1) извините за ссылку api, это был просто старый код, который я забыл удалить. (2) любить переписывать/исправлять - гораздо лучше и будет использовать этот подход во всем моем коде в будущем. (3) запуская некоторые проблемы с Unicode с вашим кодом - не уверен, почему, но будет делать некоторые исследования. – timepilot

ответ

8

Не было бы излишним использовать рамки для чего-то подобного; Рамки python, как правило, очень легки и удобны в работе, и вам будет намного проще добавлять функции на ваш крошечный сайт. Но это не требуется; Я предполагаю, что вы делаете это для учебных целей и говорите о том, как я изменил код.

Вы используете шаблоны без механизма шаблонов в своей функции WebOutput; есть все виды опрятных языков шаблонов для python, мой любимый из которых - mako. Если код в этой функции когда-либо становится более привлекательным, чем в настоящее время, я бы разбил его на шаблон; Я покажу вам, как это будет выглядеть в одно мгновение. Но во-первых, я хотел бы использовать многострочные строки, чтобы заменить все эти f.write, и строка подстановки вместо добавления строк:

f.write("""<html> 
<title>python newb's twitter search</title> 
<head><meta http-equiv='refresh' content='60'></head> 
<body> 
<h1 style='font-size:150%'>Python Newb's Twitter Search</h1> 
<h2 style='font-size:125%'>Searching Twitter for: %s</h2> 
<h2 style='font-size:125%'>%s (updates every 60 seconds)</h2>""" % (query, time.ctime())) 

for datum in reversed(data): 
    f.write("<p style='font-size:90%'>%s</p>" % (datum)) 

f.write("</body></html>") 

Также обратите внимание, что я упростил свой цикл немного; Я объясню дальше, если то, что я ставлю, не имеет смысла.

Если вы должны были преобразовать функцию WebOutput в Мако, вы бы сначала импортировать Мако в верхней части файла с:

import mako 

Тогда вы бы заменить все тело WebOutput() с:

f = file("outw.html", "w") 
data = reversed(data) 
t = Template(filename='/path/to/mytmpl.txt').render({"query":query, "time":time.ctime(), "data":data}) 
f.write(t) 

Наконец, вы бы сделать файл /path/to/mytmpl.txt который выглядит следующим образом:

<html> 
<title>python newb's twitter search</title> 
<head><meta http-equiv='refresh' content='60'></head> 
<body> 
<h1 style='font-size:150%'>Python Newb's Twitter Search</h1> 
<h2 style='font-size:125%'>Searching Twitter for: ${query}</h2> 
<h2 style='font-size:125%'>${time} (updates every 60 seconds)</h2> 

% for datum in data: 
    <p style'font-size:90%'>${datum}</p> 
% endfor 

</body> 
</html> 

И вы можете видеть, что приятная вещь, которую вы достигли, - это разделение вывода (или «уровня представления» в веб-терминах) на код, который захватывает и форматирует данные («слой модели» и «слой контроллера»). Это значительно облегчит вам изменение вывода вашего скрипта в будущем.

(Примечание: я не проверял код я изложенные здесь извинения, если это не совсем правильно, то должны в основном работать, хотя.)

+0

Я думаю, что обратное (data [-rpp:]) может быть упрощено для обратного (данные) (rpp - это количество элементов, возвращаемых API) – dbr

+1

Хорошая точка .... Я скопировал этот бит его диапазона(), не задумываясь. Исправлена. – llimllib

1

Проблема, с которой вы столкнетесь, заключается в том, что вам нужно будет изменить python всякий раз, когда вы хотите изменить html. Для этого случая это может быть хорошо, но это может привести к неприятностям. Я думаю, что использование чего-то с системой шаблонов имеет большой смысл. Я бы предложил посмотреть на Django. tutorial очень хорошо.

4

Я бы предложил использовать шаблон для генерации вывода, вы можете начать с buildin string.Template или попробовать что-то более эффектное, например Mako (или Cheetah, Genshi, Jinja, Kid и т. Д.).

Python имеет много хороших фреймворков, самый маленький из них будет web.py или werkzeug

Если вы хотите fullblown рамки, смотрите на Pylons или Django, но это действительно избыточна для такого проекта, как это.

5

String formatting может сделать вещи намного аккуратнее, и меньше ошибок -prone.

Простой пример, %s заменяется a title:

my_html = "<html><body><h1>%s</h1></body></html>" % ("a title") 

Или несколько раз (название то же самое, и теперь "мое содержание" отображается, когда второй %s является:

my_html = "<html><body><h1>%s</h1>%s</body></html>" % ("a title", "my content") 

Вы также можете использовать именованные ключи при выполнении %s, например %(thekey)s, что означает, что вам не нужно отслеживать, в каком порядке находятся %s. Вместо list, вы используете dictionary, который отображает ключ к значению:

my_html = "<html><body><h1>%(title)s</h1>%(content)s</body></html>" % { 
    "title": "a title", 
    "content":"my content" 
} 

Самая большая проблема с вашим скриптом, вы используете глобальную переменную (data). гораздо лучше всего было бы:

  • search_results вызовов, с аргументом «SwineFlu»
  • search_results возвращает список результатов, сохранить результат в переменной
  • вызова WebOutput, с поиском приводит переменную в качестве аргумента
  • WebOutput возвращает строку, содержащую ваш HTML
  • написать возвращаемый HTML в файл

WebOutput вернет HTML (как строку) и напишет его в файл. Что-то вроде:

results = SearchResults("swineflu", 25) 
html = WebOutput(results) 
f = open("outw.html", "w") 
f.write(html) 
f.close() 

Наконец, модуль twitterd требуется только при доступе к данным, которая требует входа в систему. Публичная шкала времени, ну, общедоступна и может быть доступна без аутентификации, поэтому вы можете удалить импорт twitterd и строку api =.Если же хотите использовать twitterd, вы должны сделать что-то с переменной api, например:

api = twitterd.Api(username='username', password='password') 
statuses = api.GetPublicTimeline() 

Итак, как я мог бы написать сценарий является:

import time 
import urllib 
import simplejson 

def search_results(query, rpp = 25): # 25 is default value for rpp 
    url = "http://search.twitter.com/search.json?q=%s&%s" % (query, rpp) 

    jsonResults = simplejson.load(urllib.urlopen(url)) 

    data = [] # setup empty list, within function scope 
    for tweet in jsonResults["results"]: 
     # Unicode! 
     # And tweet is a dict, so we can use the string-formmating key thing 
     data.append(u"%(from_user)s | %(text)s" % tweet) 

    return data # instead of modifying the global data! 

def web_output(data, query): 
    results_html = "" 

    # loop over each index of data, storing the item in "result" 
    for result in data: 
     # append to string 
     results_html += " <p style='font-size:90%%'>%s</p>\n" % (result) 

    html = """<html> 
    <head> 
    <meta http-equiv='refresh' content='60'> 
    <title>python newb's twitter search</title> 
    </head> 
    <body> 
     <h1 style='font-size:150%%'>Python Newb's Twitter Search</h1> 
     <h2 style='font-size:125%%'>Searching Twitter for: %(query)s</h2> 
     <h2 style='font-size:125%%'> %(ctime)s (updates every 60 seconds)</h2> 
    %(results_html)s 
    </body> 
    </html> 
    """ % { 
     'query': query, 
     'ctime': time.ctime(), 
     'results_html': results_html 
    } 

    return html 


def main(): 
    query_string = "swineflu" 
    results = search_results(query_string) # second value defaults to 25 

    html = web_output(results, query_string) 

    # Moved the file writing stuff to main, so WebOutput is reusable 
    f = open("outw.html", "w") 
    f.write(html) 
    f.close() 

    # Once the file is written, display the output to the terminal: 
    for formatted_tweet in results: 
     # the .encode() turns the unicode string into an ASCII one, ignoring 
     # characters it cannot display correctly 
     print formatted_tweet.encode('ascii', 'ignore') 


if __name__ == '__main__': 
    main() 
# Common Python idiom, only runs main if directly run (not imported). 
# Then means you can do.. 

# import myscript 
# myscript.search_results("#python") 

# without your "main" function being run 

(2) в какой момент будет подходящим для приложения подходящим для приложения? Overkill?

Я бы сказал, всегда использовать веб-рамку (с некоторыми исключениями)

Теперь, это может показаться странным, учитывая все время я только потратил объяснение исправления в свой сценарий .. но с вышеназванным модификации вашего скрипта, это невероятно легко сделать, так как все было хорошо функционально!

Используя CherryPy, который представляет собой простую структуру HTTP для Python, вы можете легко отправлять данные в браузер, а не постоянно писать файл.

Предполагается, что приведенный выше сценарий сохраняется как twitter_searcher.py.

Примечание. Я никогда раньше не использовал CherryPy, это просто пример HelloWorld на домашней странице CherryPy, с несколькими строками, скопированными из функции main() этого выше скрипта!

import cherrypy 

# import the twitter_searcher.py script 
import twitter_searcher 
# you can now call the the functions in that script, for example: 
# twitter_searcher.search_results("something") 

class TwitterSearcher(object): 
    def index(self): 
     query_string = "swineflu" 
     results = twitter_searcher.search_results(query_string) # second value defaults to 25 
     html = twitter_searcher.web_output(results, query_string) 

     return html 
    index.exposed = True 

cherrypy.quickstart(TwitterSearcher()) 

Сохранить и запустить этот сценарий, затем перейдите к http://0.0.0.0:8080/ и он будет показывать свою страницу!

Проблема с этим, при каждой загрузке страницы он будет запрашивать API Twitter. Это не будет проблемой, если вы просто используете его, но с сотнями (или даже десятками) людей, которые смотрят на страницу, он начнет замедляться (и вы могли бы получить ограничение по скорости/заблокировать API-интерфейс Twitter, в конечном итоге)

Решение в основном возвращается к началу. Вы должны написать (кэш) результат поиска на диск, переименовать твиттер, если данные более чем на 60 секунд. Вы также можете заглянуть в CherryPy's caching options .. но этот ответ становится довольно абсурдно долго.

Смежные вопросы