Using Django with GAE Python 后臺抓取多個網(wǎng)站的頁面全文
一直想做個能幫我過濾出優(yōu)質(zhì)文章和博客的平臺 給它取了個名 叫Moven。。 把實現(xiàn)它的過程分成了三個階段:
1. Downloader: 對于指定的url的下載 并把獲得的內(nèi)容傳遞給Analyser--這是最簡單的開始
2. Analyser: 對于接受到的內(nèi)容,用Regular Expression 或是 XPath 或是 BeautifulSoup/lxml 進行過濾和簡化--這部分也不是太難
3. Smart Crawler: 去抓取優(yōu)質(zhì)文章的鏈接--這部分是最難的:
Crawler的話可以在Scrapy Framework的基礎(chǔ)上快速的搭建
但是判斷一個鏈接下的文章是不是優(yōu)質(zhì) 需要一個很復(fù)雜的算法
最近就先從Downloader 和 Analyser 開始: 最近搭了一個l2z story 并且還有一個 Z Life 和 Z Life@Sina 還有一個她的博客 做為一個對Downloader 和 Analyser的練習(xí) 我就寫了這個東西來監(jiān)聽以上四個站點 并且把它們的內(nèi)容都同步到這個站上:
http://l2zstory.appspot.com
App 的特色
這個站上除了最上面的黑色導(dǎo)航條 和 最右邊的About This Site 部分外, 其他的內(nèi)容都是從另外的站點上自動獲得
原則上, 可以添加任何博客或者網(wǎng)站地址到這個東西。。。當然因為這個是L2Z Story..所以只收錄了四個站點在里面
特點是: 只要站點的主人不停止更新, 這個東西就會一直存在下去---這就是懶人的力量
值得一提的是, Content 菜單是在客戶端用JavaScript 自動生成的--這樣就節(jié)約了服務(wù)器上的資源消耗
這里用的是html全頁面抓取 所以對那些feed沒有全文輸出的站點來說, 這個app 可以去把它要隱藏的文字抓來
在加載的時候會花很多時間因為程序會自動到一個沒有全文輸出的頁面上抓取所有的文章列表,作者信息,更新時間,以及文章全文。。所以打開的時候請耐心。。。下一步會加入數(shù)據(jù)存儲部分,這樣就會快了。。
技術(shù)準備
前端:
1. CSS 在信奉簡單之上的原則上 twitter的bootstrap.css滿足了我大多數(shù)的要求 個人超喜歡它的 Grid System
2. Javascript上, 當然選用了jQuery 自從我開始在我的第一個小項目上用了jQuery 后 我就愛上了它 那個動態(tài)的目錄系統(tǒng)就是用jQuery快速生成的
為了配合bootstrap.css, bootstrap-dropdown.js 也用到了
服務(wù)器:
這個app有兩個版本:
一個跑在我的Apache上, 但是因為我的網(wǎng)絡(luò)是ADSL, 所以ip一直會變基本上只是我在我的所謂的局域網(wǎng)內(nèi)自測用的。。這個版本是純Django的
另一個跑在Google App Engine上 地址是 http://l2zstory.appspot.com 在把Django 配置到GAE的時候我花了很多功夫才把框架搭起來
詳情請見: Using Django with Google App Engine GAE: l2Z Story Setup-Step 1 http://blog.sina.com.cn/s/blog_6266e57b01011mjk.html
后臺:
主要語言是Python--不解釋, 自從認識Python后就沒有離開它
主要用到的module是
1. BeautifulSoup.py 用于html 的解析--不解釋
2. feedparser.py 用于對feed xml的解析--網(wǎng)上有很多人說GAE不支持feedparser..這里你們得到答案了。。可以。。這里我也是花了很久才弄明白到底是怎么回事。??傊唵沃v就是: 可以用!但是feedparser.py這個文件必須放到跟app.yaml同一個目錄中 不然會出現(xiàn)網(wǎng)上眾人說的不可以import feedparser的情況
數(shù)據(jù)庫:
Google Datastore: 在下一步中, 這個程序會每隔30分鐘醒來 逐一查看各個站點有沒有更新并抓取更新后的文章并存入Google 的Datastore中
App 的配置
遵循Google的規(guī)則, 配置文件app.yaml 如下:
這里主要是定義了一些static directory--css 和 javascript的所在地
application: l2zstory
version: 1
runtime: python
api_version: 1
handlers:
- url: /images
static_dir: l2zstory/templates/template2/images
- url: /css
static_dir: l2zstory/templates/template2/css
- url: /js
static_dir: l2zstory/templates/template2/js
- url: /js
static_dir: l2zstory/templates/template2/js
- url: /.*
script: main.py
URL的配置
這里采用的是Django 里的正則表達式
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()
urlpatterns = patterns('',
# Example:
# (r'^l2zstory/', include('l2zstory.foo.urls')),
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
# (r'^admin/(.*)', admin.site.root),
(r'^$','l2zstory.stories.views.L2ZStory'),
(r'^YukiLife/','l2zstory.stories.views.YukiLife'),
(r'^ZLife_Sina/','l2zstory.stories.views.ZLife_Sina'),
(r'^ZLife/','l2zstory.stories.views.ZLife')
)
Views的細節(jié)
對Django比較熟悉的人應(yīng)該會從url的配置中看到view的名字了 我只把L2ZStory的這個view貼出來因為其他的在view里的架構(gòu)至少是差不多的
#from BeautifulSoup import BeautifulSoup
from PyUtils import getAboutPage
from PyUtils import getPostInfos
def L2ZStory(request):
url="feed://l2zstory.wordpress.com/feed/"
about_url="http://l2zstory.wordpress.com/about/"
blog_type="wordpress"
htmlpages={}
aboutContent=getAboutPage(about_url,blog_type)
if aboutContent=="Not Found":
aboutContent="We use this to tell those past stories..."
htmlpages['about']={}
htmlpages['about']['content']=aboutContent
htmlpages['about']['title']="About This Story"
htmlpages['about']['url']=about_url
PostInfos=getPostInfos(url,blog_type,order_desc=True)
return render_to_response('l2zstory.html',
{'PostInfos':PostInfos,
'htmlpages':htmlpages
})
這里主要是構(gòu)建一個dictionary of dictionary htmlpages 和一個list of dictionary PostInfos
htmlpages 主要是存貯站點的 About, Contact US 之類的頁面
PostInfos 會存貯所有文章的 內(nèi)容, 作者, 發(fā)布時間 之類的
這里面最重要的是PyUtils。。這是這個app的核心
PyUtils的細節(jié)
我把一些我認為比較重要的細節(jié)加深了 并加了評論
import feedparser
import urllib2
import re
from BeautifulSoup import BeautifulSoup
header={
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:8.0.1) Gecko/20100101 Firefox/8.0.1',
}
#用來欺騙網(wǎng)站的后臺。。象新浪這類的網(wǎng)站對我們這類的app十分不友好。。。希望它們可以多象被墻掉的wordpress學(xué)一學(xué)。。
timeoutMsg="""
The Robot cannot connect to the desired page due to either of these reasons:
1. Great Fire Wall
2. The Blog Site has block connections made by Robots.
"""
def getPageContent(url,blog_type):
try:
req=urllib2.Request(url,None,header)
response=urllib2.urlopen(req)
html=response.read()
html=BeautifulSoup(html).prettify()
soup=BeautifulSoup(html)
Content=""
if blog_type=="wordpress":
try:
for Sharesection in soup.findAll('div',{'class':'sharedaddy sd-like-enabled sd-sharing-enabled'}):
Sharesection.extract()
for item in soup.findAll('div',{'class':'post-content'}):
Content+=unicode(item)
except:
Content="No Post Content Found"
elif blog_type=="sina":
try:
for item in soup.findAll('div',{'class':'articalContent '}):
Content+=unicode(item)
except:
Content="No Post Content Found"
#對于不同的網(wǎng)站類型 應(yīng)用不同的過濾器
except:
Content=timeoutMsg
return removeStyle(Content)
def removeStyle(Content):
#add this to remove all the img tag : (<img +(\w=\".*\")>)|(</img>)|(src=\".*\")|
patn=re.compile(r"(align=\".*\")|(id=\".*\")|(class=\"*\")|(style=\".*\")|(</font>)|(<font.*\">)|(<embed +(\w*=\".*\")>)|(</embed>)")
replacepatn=""
Content=re.sub(patn,replacepatn,Content)
#運用正則表達式把抓取的內(nèi)容中那些格式通通去掉 這樣得到的文字比較純粹
return Content
def getPostInfos(url,blog_type,order_desc=False):
feeds=feedparser.parse(url)
PostInfos=[]
if order_desc:
items=feeds.entries[::-1]
else:
items=feeds.entries
Cnt=0
for item in items:
PostInfo={}
PostInfo['title']=item.title
PostInfo['author']=item.author
PostInfo['date']=item.date
PostInfo['link']=item.link
if blog_type=="wordpress":
Cnt+=1
if Cnt<=8:
PostInfo['description']=getPageContent(item.link,blog_type)
else:
PostInfo['description']=removeStyle(item.description)
elif blog_type=="sina":
PostInfo['description']=removeStyle(item.description)
PostInfos.append(PostInfo)
return PostInfos
template 的概覽
在簡單之上的原則的鼓舞下, 所有的站點都統(tǒng)一使用一個template 這個template 只接受兩個變量--前文中提到的htmlpages 和 PostInfos
重要的片斷是:
<div class="page-header">
<a href="{{htmlpages.about.url}}" name="{{htmlpages.about.title}}"><h3>{{htmlpages.about.title}}</h3></a>
</div>
<p>
{{htmlpages.about.content}}
</p>
{%for item in PostInfos%}
<div class="page-header">
<a href="{{item.link}}" name="{{item.title}}"><h3>{{item.title}}</h3></a>
</div>
<p><i>author: {{item.author}} date: {{item.date}}</i></p>
<p>{{item.description}}</p>
{%endfor%}
</div>
總結(jié)
一句話, 我愛死Python了
兩句話, 我愛死Python了,我愛死Django了
三句話, 我愛死Python了,我愛死Django了,我愛死jQuery了。。。
相關(guān)文章
python 動態(tài)渲染 mysql 配置文件的示例
這篇文章主要介紹了python 動態(tài)渲染 mysql 配置文件的示例,幫助大家更好的理解和使用python,感興趣的朋友可以了解下2020-11-11Tensorflow Summary用法學(xué)習(xí)筆記
這篇文章主要介紹了Tensorflow Summary用法學(xué)習(xí)筆記,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-0110 行Python 代碼實現(xiàn) AI 目標檢測技術(shù)【推薦】
這篇文章主要介紹了10 行Python 代碼,實現(xiàn) AI 目標檢測技術(shù),看完了代碼,我們在一起聊聊目標檢測背后的技術(shù)背景,并解讀這10行Python代碼的由來和實現(xiàn)原理。感興趣的朋友跟隨小編一起看看吧2019-06-06Pycharm虛擬環(huán)境創(chuàng)建并使用命令行指定庫的版本進行安裝
Pycharm創(chuàng)建的項目,使用了虛擬環(huán)境,對庫的版本進行管理,有些項目的對第三方庫的版本要求不同,可使用虛擬環(huán)境進行管理,直接想通過pip命令安裝可以參考下本文的操作步驟2022-07-07在django項目中導(dǎo)出數(shù)據(jù)到excel文件并實現(xiàn)下載的功能
這篇文章主要介紹了在django項目中導(dǎo)出數(shù)據(jù)到excel文件并實現(xiàn)下載的功能,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03