Django邊學邊做(二)

3、實例一:抓取電驢鏈接(BeautifulSoup解析網頁)

  3.1 BeautifulSoup庫介紹

  BeautifulSoup是python開源的html解析庫,能夠用來很方便的操縱html的dom元素,製作網頁爬蟲的利器。 

  3.2 home頁面實現

  home頁面位於整個網頁左側的frame中,顯示的是電驢的電子圖書目錄。我們使用BeautifulSoup抓取電驢的電子圖書總目錄的頁面,從中我們分析出電子圖書的種類,然後顯示在home頁面中。

  1)首先在verycdhelper下建立logic目錄,與templates位於同一層次,在logic目錄下新增verycdhelper.py,這就是我們實現網頁抓取邏輯的地方。此目錄中建立一個空的__init__.py文件,以便verycdhelper.py可以被外部的文件引用。

  2)在verycdhelper.py中定義get_book_categories函數獲取圖書種類:

from bs4 import BeautifulSoup
import urllib2
import re

class book_category:
    def __init__(self, href, category):
        self.href = href
        self.category = category

def get_book_categories():
    verycd_home_url = urllib2.urlopen(
    'http://www.verycd.com/archives/book/')
    verycd_home = BeautifulSoup(verycd_home_url.read())

    div_nav = verycd_home.find("div", id="nav")
    book_categories = []
    for a in div_nav.find_all("a", href=re.compile("book/[a-zA-z]+/$")):
        text = a.get_text()
        pos = text.find('(')
        category = text[0:pos]
        book_categories.append(book_category(a['href'], category))

    return book_categories


  可以看到book_category類收集了書籍種類和此種類書籍的頁面鏈接。verycd_home是一個BeautifulSoup對象,以verycd的書籍總目錄頁面的url爲初始化參數。然後我們在此頁面中找到id=“nav”的<div>頁面元素,此元素中包含了所有的書籍種類鏈接。在此<div>中遍歷所有的<a>元素,元素的鏈接需要匹配book/[a-zA-z]+/$,即以一個或多個字符結尾。在每一個<a>中,我們取得a['href']屬性爲此種類書籍的頁面鏈接。我們分析<a>的文本子元素a.get_text(),取出'('之前的文本即爲書籍種類。

  3)我們還需要修改views.py,在home函數中調用以上函數:

from django.http import HttpResponse
from django.template.loader import get_template
from django.shortcuts import render_to_response
from logic.verycdhelper import *

def home(request):
    book_categories = get_book_categories()
	
    return render_to_response('home.html',
        {'category_list':book_categories})
  我們可以看到,傳遞給home.html模板的時候,我們傳遞了一個字典,字典的只有一項,是書籍的種類列表。

  4)我們看看home.html模板現在的樣子,是怎樣用到此book_categories的:

<html>
	<head>
		<h1> VeryCD Book Menu </h1>
		<hr>
	</head>
	<body>
		<ul>
			{% for cty in category_list %}
				<li><a href={{cty.href}}  target="display">{{ cty.category }}</a></li>
			{% endfor %}
		</ul>
	</body>

</html>
  在<body>部分,遍歷category_list列表,生成一列<li>項目,每項是一個超鏈接,點擊超鏈接會顯示頁面到名爲display的frame中。此<a>顯示的文本是cty.category。

  5)運行程序,我們看看效果:

  3.3 顯示書籍種類頁面的模板book_page_list.html實現

  我們點擊左邊的目錄項,應當在後側frame中顯示此項書籍種類的頁面序號列表,book_page_list.html即是此頁面的模板。

  1)首先,我們要從verycd抓取某一書籍種類的頁面,將此頁面的書籍序號列表都分析出來,顯示到book_page_list.html中。

  2)在verycdhelper.py中定義get_book_page_list函數,根據書籍類別獲取書籍的頁面序號列表:

class book_page:
    def __init__(self, href, page):
	self.href = href
	self.page = page

def get_book_page_list(category):
    verycd_archive_book_str = 'http://www.verycd.com/archives/book/'
    book_list_url = urllib2.urlopen(verycd_archive_book_str + category)
    book_list = BeautifulSoup(book_list_url.read())
 
    div_cont = book_list.find("div", id="content")
    dl_page_list = div_cont.find("dl")
    book_page_list = []
    for a in dl_page_list.find_all("a"):
        book_page_list.append(book_page(a['href'], a.get_text()))
    
    return book_page_list
  先打開verycd的書籍種類的序號頁面,然後我們找到id=“content"的<div>,在此<div>中我們找到<dl>,在此<dl>中我們找到所有的<a>,這些<a>標籤就是書籍序號。我們定義了book_page類存儲書籍序號和書籍序號指向的超鏈接。

  3)我們修改views.py和urls.py,增加來匹配get_book_page_list.html模板的函數:

views.py:

def book_page_list(request, category):
    book_page_list = get_book_page_list(category)

    return render_to_response('book_page_list.html',
	{'book_page_list':book_page_list,
	 'category':category,
        })
urls.py:

url(r'^archives/book/([a-zA-z]*)/$', book_page_list)
  這裏book_page_list函數調用了網頁抓取模塊,將書籍類別和書籍頁面序號列表傳給book_page_list.html模板,url匹配所有以字符結尾,以archives開頭的url。

  4)get_book_page_list.html模板:

<html>
	<body>
		<h1>{{category}}</h1>
		<ul>
			{% for pg in book_page_list %}
				<li><a href={{pg.href}} target="display">{{pg.page}}</a></li>
			{% endfor %}
		</ul>
	</body>
</html>
  此模板將book_page_list中的頁面序號鏈接顯示到右側的frame中,其中每一個鏈接指向的頁面也都顯示到右側的名爲display的frame中。
 5)我們點擊小說目錄,顯示效果如下:

  3.4 書籍的書名列表頁book_list.html實現

  我們看到,上一節中列出了書籍序號列表,那我們期望點擊序號列表,可以看到所有的書名。比如,點擊No.1-100,我們可以看到1-100的書籍名稱。

  1)在verycdhelper.py中,增加抓取頁面的函數,此函數根據書籍類別和頁面序號獲取書籍的列表:

class book_info:
    def __init__(self, href, title):
	self.href = href
	self.title = title

def get_book_list(category, page):
    verycd_archive_book_str = 'http://www.verycd.com/archives/book/'
    book_list_url = urllib2.urlopen(verycd_archive_book_str + category
	+ '/' + page)
    book_list = BeautifulSoup(book_list_url.read())
    div_res = book_list.find("div", id="resList")
    book_list = []
    for a in div_res.find_all("a"):
	book_list.append(book_info(a['href'], a['title']))

    return book_list
  我們從verycd的書籍列表頁面找到id="resList"的<div>,在此<div>下找到所有的<a>,此<a>標籤的鏈接和標題就是書籍詳細信息的鏈接以及書名。

  2)在views.py和urls.py中增加此book_list.html的調用:

views.py:

def book_list(request, category, page):
    book_info_list = get_book_list(category, page)
    book_category = '/archives/book/' + category
    back_to_list = 'Back To List'
	
    return render_to_response('book_list.html',
	{'book_info_list':book_info_list,
	 'category':book_category,
	 'back_to_list':back_to_list,
	})
  我們增加了一項back_to_list,返回到頁面序號列表頁面的鏈接。

urls.py:

url(r'^archives/book/([a-zA-z]*)/(\d{5}.html)/$', book_list)
  3)我們增加book_list.html的模板:

<html>
	<body>
		<ul>
			<li><a href={{category}} target="display">{{back_to_list}}</a></li>
			{% for book_info in book_info_list %}
				<li><a href={{book_info.href}} target="display">{{book_info.title}}</a></li>
			{% endfor %}
		</ul>
	</body>
</html>
  這裏我們增加了back_to_list的鏈接,指向書籍類別的序號列表頁面,並且將書名都列出,每個書名對應的詳細信息鏈接會顯示到名爲display的frame中。

  4)看一下效果,點解No.1-100後:

  3.5 顯示書籍的具體信息book_detail.html的實現

  那麼我們最後一步就是顯示書籍的具體信息了,顯示下載鏈接。

  1)在verycdhelper.py中增加抓取書籍詳細信息的函數get_book_detail:

class book_detail:
    def __init__(self, title, style, info, description, href_list):
	self.title = title
	self.style = style
	self.info = info
	self.description = description
	self.href_list = href_list

def get_book_detail(book_id):
    download_url_str = 'http://www.verycd.gdajie.com/'
    url_final = download_url_str + '/topics/' + book_id
    html_download = urllib2.urlopen(url_final)
    soup_lk = BeautifulSoup(html_download.read())

    div_thumb = soup_lk.find("div", class_="thumb120")
    title = div_thumb.a['title']
    style = div_thumb.a['style']
    start = style.find('(')
    end = style.find(')')
    style = style[start+1:end]
	
    div_info = soup_lk.find("div", class_="info")
    info = div_info.strings
	
    div_desc = soup_lk.find("div", class_="description")
    description = div_desc.strings
	
	
    
    table = soup_lk.find("table", id="emuleFile")
    h = table.a.get('href')
    html_target = urllib2.urlopen(h)
    soup_h = BeautifulSoup(html_target.read())
    div = soup_h.find("div", id="detail")
	
    href_list = []
    for a in div.find_all('a'):
	href_list.append(a['href'])

    return book_detail(title, style, info, description, href_list)
可以看到,我們在book_detail中記錄了每本書的書籍名、書籍圖片、書籍簡介、書籍摘要和下載列表。我們首先抓取到下載網站的書籍下載頁面,找到class_="info"的<div>,從<div>中取出簡介,找到class_=“description”的<div>,取出摘要。注意這裏,<div>的屬性class在BeautifulSoup中是以class_表示的。然後我們找到id="emuleFile"的<table>,從中找到下載鏈接頁面,創建一個新的頁面抓取對象soup_h,在此對象中找到id="detail"的<div>,從此頁面中我們找到所有的<a>標籤,即是下載列表。

  2)增加views.py和urls.py的函數:

views.py:

def book_detail(request, book_id):
    book_detail = get_book_detail(book_id)
    return render_to_response('book_detail.html',
	{'book_detail':book_detail,
	})
urls.py:

url(r'^topics/(\d+)/$', book_detail),
這裏我們匹配的是形如topics/23456/的url

  3)增加book_detail.html模板

<html>
	<body>
		<div>
			<h1>{{book_detail.title}}</h1>
			<img src={{book_detail.style}}>
		</div>
		<hr>
		<ul>
			<li>
			{% for line in book_detail.info %}
				<p>{{line}}</p>
			{% endfor %}
			</li>
			<li>
			{% for line in book_detail.description %}
				<p>{{line}}</p>
			{% endfor %}
			</li>
			<hr>
			{% for addr in book_detail.href_list %}
				<li><a href={{addr}} target="display">{{addr}}</a></li>
			{% endfor %}
		</ul>
	</body>
</html>
我們顯示了標題,並且顯示了圖書的封面圖片,然後對於info和description中的文字進行了分行的顯示,在頁面最後我們列出了下載列表。

  4)我們最後來看看效果如下:

右側的頁面滾動到最後,如下:

  3.6 小結

  到此,我們就建立了一個完整的Django程序,只使用了View和Url這兩個組件,搭建了從電驢上抓取有用信息的網站。這個網站簡單實用,我自己都在使用它。今後,我在學習Django的過程中會逐步用到其他更多的功能,來完善這個網站或創建新的web應用。


發佈了31 篇原創文章 · 獲贊 19 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章