虽然我已经玩了几个月的python(只是一个业余爱好者),但我对网络编程知之甚少(一点点html,零javascript等).也就是说,我有一个当前的项目让我第一次看到网络编程.这让我想问:
谢谢答案,我取得了一些进展.现在,我只是使用python和html.我无法发布我的项目代码,因此我使用twitter搜索编写了一个小例子(请参阅下文).
我的问题是:
(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)
Run Code Online (Sandbox Code Playgroud)
使用这样的框架并不过分; 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>")
Run Code Online (Sandbox Code Playgroud)
另请注意,我简化了你的for循环; 我会进一步解释我所说的是没有意义的.
如果您要将WebOutput函数转换为Mako,则首先要在文件顶部导入mako:
import mako
Run Code Online (Sandbox Code Playgroud)
然后你将用以下内容替换整个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)
Run Code Online (Sandbox Code Playgroud)
最后,您将创建一个如下所示的文件/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>
Run Code Online (Sandbox Code Playgroud)
您可以看到,您完成的好处是将输出(或Web术语中的"视图层")与抓取和格式化数据的代码("模型层"和"控制器层")分开.这将使您将来更容易更改脚本的输出.
(注意:我没有测试我在这里提供的代码;如果它不太正确,请道歉.它应该基本上可以工作)
字符串格式化可以使事情变得更整洁,并且更不容易出错.
简单的例子,%s被替换为a title:
my_html = "<html><body><h1>%s</h1></body></html>" % ("a title")
Run Code Online (Sandbox Code Playgroud)
或多次(标题相同,现在"我的内容"显示在第二个%s位置:
my_html = "<html><body><h1>%s</h1>%s</body></html>" % ("a title", "my content")
Run Code Online (Sandbox Code Playgroud)
这样做时,也可以使用名为键%s,如%(thekey)s,这意味着你不必跟踪了解其顺序%s是相反的一个,列表,你可以使用一个字典,它映射的关键价值:
my_html = "<html><body><h1>%(title)s</h1>%(content)s</body></html>" % {
"title": "a title",
"content":"my content"
}
Run Code Online (Sandbox Code Playgroud)
您的脚本最大的问题是,您正在使用全局变量(data).一个多更好的方式是:
WebOutput将返回HTML(作为字符串),并将其写入文件.就像是:
results = SearchResults("swineflu", 25)
html = WebOutput(results)
f = open("outw.html", "w")
f.write(html)
f.close()
Run Code Online (Sandbox Code Playgroud)
最后,只有在访问需要登录的数据时才需要twitterd模块.公共时间表是公开的,无需任何身份验证即可访问,因此您可以删除twitterd导入和api =行.如果您确实想使用twitterd,则必须对api变量执行某些操作,例如:
api = twitterd.Api(username='username', password='password')
statuses = api.GetPublicTimeline()
Run Code Online (Sandbox Code Playgroud)
所以,我编写脚本的方式是:
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
Run Code Online (Sandbox Code Playgroud)
(2)框架在什么时候适合这样的应用程序?矫枉过正?
我会说总是使用一个web框架(有一些例外)
现在,这可能看起来很奇怪,因为我只是花了一些时间来解释你的脚本修复...但是,通过对你的脚本的上述修改,它非常容易做到,因为一切都很好地运行了!
使用CherryPy,这是一个非常简单的Python HTTP框架,您可以轻松地将数据发送到浏览器,而不是经常编写文件.
这假定上面的脚本保存为twitter_searcher.py.
注意我之前从未使用过CherryPy,这只是CherryPy主页上的HelloWorld示例,从上面脚本的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())
Run Code Online (Sandbox Code Playgroud)
保存并运行该脚本,然后浏览http://0.0.0.0:8080/并显示您的页面!
这个问题,在每个页面加载它将查询Twitter API.如果只是你使用它,这不会是一个问题,但是有数百(甚至数十)人在看页面,它会开始变慢(你可能会被twitter API限制/阻止,最终)
解决方案基本上回到了开始..你会将搜索结果写入(缓存)到光盘,如果数据超过60秒,则重新搜索twitter.您还可以查看CherryPy的缓存选项 ..但这个答案变得相当荒谬了......
| 归档时间: |
|
| 查看次数: |
2944 次 |
| 最近记录: |