python小程序:豆瓣图书的网络爬虫

学习python有一段时间,一直都是看书学,写点书上的小例子,终于把书看完了,想着写一个爬虫锻炼一下。其实用python写爬虫还是挺简单的,一个难点是正则表达式,因为一般用python把网页整个源代码爬下来,然后根据网页的内容结构把我们需要的内容给抓出来。作为一名后端程序员,平时也只是偶尔写写前端页面,偶尔遇上一些需要正则表达式的,也就是在网上找了一下,没有怎么学,所以写这个之前还补了一下正则表达式。

urllib2模块和urllib模块类似,用来打开URL并从中获取数据。与urllib模块不同的是,urllib2模块不仅可以使用urlopen()函数还可以自定义opener来访问网页。但同时要注意:urlretrieve()函数是urllib模块中的,urllib2模块中不存在该函数。但是使用urllib2模块时一般都离不开urllib模块,因为post的数据需要使用urllib.urlencode()函数来编码。

先来介绍一下程序中用到的urllib2方法:
urlopen(url, [,data, [timeout]])
urlopen()是最简单的请求方式,它打开url并返回类文件对象,并且使用该对象可以读取返回的内容。参数url可以是包含url的字符串,也可以是urllib2.request类的实例。data是经过编码的post数据(一般使用urllib.urlencode()来编码)。timeout是可选的超时期(以秒为单位),供所有阻塞操作内部使用。
假设urlopen()返回的文件对象u,它支持下面的这些常用的方法:
u.read([nbytes]) 以字节字符串形式读取nbytes个数据
u.readline() 以字节字符串形式读取单行文本
u.readlines() 读取所有输入行然后返回一个列表
u.close() 关闭链接
u.getcode() 返回整数形式的HTTP响应代码,比如成功返回200,未找到文件时返回404
u.geturl() 返回所返回的数据的实际url,但是会考虑发生的重定向问题
u.info() 返回映射对象,该对象带有与url关联的信息,对HTTP来说,返回的服务器响应包含HTTP包头。对于FTP来说,返回的报头包含'content-length'。对于本地文件,返回的报头包含‘content-length’和'content-type'字段。
要注意的是,类文件对象u以二进制模式操作。如果需要以文本形式处理响应数据,则需要使用codecs模块或类似方式解码数据。

关于正则表达式,可以参考一下这篇文章:Python正则表达式指南

需要注意的是是否匹配多行模式以及贪婪模式与非贪婪模式。

二、这个衔接是《暗时间》的豆瓣介绍

http://book.douban.com/subject/6709809/

通过查看源码分析,就会发现

有class="ua-windows ua-webkit book-new-nav"的页面是图书介绍页面,而其中标题结构为<title>暗时间 (豆瓣)</title>
出版社、出版年、页数、定价等结构如下:
<span class="pl">出版社</span> (.*)<br/>

稍微难一点的是作者:

<span>

<span class="pl"> 作者</span>:

<a class="" href="/search/%E5%88%98%E6%9C%AA%E9%B9%8F">刘未鹏</a>

</span><br/>

涉及到了换行,开始使用

<span class="pl"> 作者</span>.*<a class="" href=.*>(.*)</a>去匹配,查出来的作者不是空就是豆瓣广告,这首因为默认使用贪婪模式匹配,后来改成如下使用非贪婪模式就正确了

<span class="pl"> 作者</span>.*?<a class="" href=.*?>(.*?)</a>

全部代码如下:

#coding=utf-8
"""
这是一个抓取豆瓣图片源代码,并从中提取相关内容的python小爬虫
"""
import sys
import urllib2
import re

def get_book(packet):
	tmp = re.search(r'<html lang(.*) book-new-nav">',packet)
	if tmp is not None:
		print "It's Book"
		title = re.search(r'<title>(.*)\(豆瓣\)</title>',packet)
		print '书名:' + title.group(1).strip()
		author = re.search(r'<span class="pl"> 作者</span>.*?<a class="" href=.*?>(.*?)</a>',packet,re.S)
		if author:
			print '作者:' + author.group(1).strip()
		cbs = re.search(r'<span class="pl">出版社:</span>(.*)<br/>',packet)
		if cbs:
			print '出版社:' + cbs.group(1).strip()
		price = re.search(r'<span class="pl">定价:</span>(.*)<br/>',packet)
		print '定价:' + price.group(1).strip()

	else:
		print "It's not Book"

def douban_book(url):
	try:
		response = urllib2.urlopen(url)
		content = response.read()
		get_book(content)
	except urllib2.URLError,e:
		if hasattr(e,"reason"):
			print 'Failed to reach the server'
			print "The reason:",e.reason
		elif hasattr(e,"code"):
			print "The server couldn't fulfill the request"
			print "Error code:",e.code
			print "Return content:",e.read()
	else:
		pass
	

if __name__ == '__main__':
	url = 'http://book.douban.com/subject/222222/'
	packet = douban_book(url)
	if packet is None:
		sys.exit(0)

结果如下图所示:

douban

拓展:可以看到豆瓣图书的url都是http://book.douban.com/subject/加上一个数字,所以可以写一个循环,就可以统计一下豆瓣有多少图书了,有空试一下。

评论

  1. GSM
    10 年前
    2014-8-28 10:17:26

    可以看到豆瓣图书的url都是http://book.douban.com/subject/加上一个数字,所以可以写一个循环,就可以统计一下豆瓣有多少图书了,有空试一下。
    这个是不太准确的,因为有很多是not found。因为豆瓣的连接是http://xxx.douban.com/subject/+数字
    XXX 可以是movie,book…

    • tcxurun
      博主
      GSM
      10 年前
      2014-8-31 18:49:56

      嗯,你说的我知道,循环里面要进行判断的,如果是not found就排除掉,不算统计的。

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇