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应用。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值