Вывод HTML на Python (первая попытка), несколько вопросов (включая код) - PullRequest
2 голосов
/ 28 апреля 2009

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

Какой самый простой способ получить вывод скрипта Python в Интернете?

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

Мои вопросы:

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

(2) в какой момент среда подойдет для такого приложения, как это? излишество?

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

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)

Ответы [ 4 ]

8 голосов
/ 29 апреля 2009

Было бы не лишним использовать фреймворк для чего-то подобного; Платформы 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>")

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

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

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>

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

(Примечание: я не тестировал представленный здесь код; извиняюсь, если он не совсем правильный. Хотя в принципе он должен работать)

5 голосов
/ 29 апреля 2009

Форматирование строк может сделать вещи намного аккуратнее и менее подвержено ошибкам.

Простой пример, %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. Вместо списка, вы используете словарь , который сопоставляет ключ со значением:

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

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

  • call 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) в какой момент среда подойдет для такого приложения, как это? излишество?

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

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

Используя 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. Это не будет проблемой, если только вы используете его, но когда сотни (или даже десятки) людей смотрят на страницу, она начнет замедляться (и вы можете получить ограничение / блокировку по скорости с помощью Twitter API, в конце концов). )

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

4 голосов
/ 28 апреля 2009

Я бы предложил использовать шаблон для генерации вывода, вы можете начать со строки buildin . Шаблон или попробовать что-нибудь более изумительное, например Mako (или Cheetah, Genshi, Джинджа, Малыш и т. Д.).

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

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

1 голос
/ 28 апреля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...