最近准备好好学学python爬虫,从网上找了个例子,爬取豆瓣读书的信息,原文地址:http://blog.youkuaiyun.com/lanbing510/article/details/45887075
代码地址:
https://raw.githubusercontent.com/lanbing510/DouBanSpider/master/doubanSpider.py
因为以前基本没接触过python,所以对代码做个简单的解析,先贴下代码如下:
#-*- coding: UTF-8 -*-
import sys
import time
import urllib
import urllib2
import requests
import numpy as np
from bs4 import BeautifulSoup
from openpyxl import Workbook
reload(sys)
sys.setdefaultencoding('utf8')
def book_spider(book_tag):
page_num=0;
count=1
book_list=[]
try_times=0
#Some User Agents
hds=[{'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'},\
{'User-Agent':'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11'},\
{'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'}]
while(1):
url="http://www.douban.com/tag/"+urllib.quote(book_tag)+"/book?start="+str(page_num*15)
time.sleep(np.random.rand()*2)
#Last Version
try:
req = urllib2.Request(url, headers=hds[page_num%len(hds)])
source_code = urllib2.urlopen(req).read()
plain_text=str(source_code)
except (urllib2.HTTPError, urllib2.URLError), e:
print e
continue
##Previous Version, IP is easy to be Forbidden
#source_code = requests.get(url)
#plain_text = source_code.text
soup = BeautifulSoup(plain_text)
list_soup = soup.find('div', {'class': 'mod book-list'})
try_times+=1;
if list_soup==None and try_times<200:
continue
elif list_soup==None or len(list_soup)<=1:
break # Break when no informatoin got after 200 times requesting
for book_info in list_soup.findAll('dd'):
title = book_info.find('a', {'class':'title'}).string.strip()
desc = book_info.find('div', {'class':'desc'}).string.strip()
desc_list = desc.split('/')
try:
author_info = '作者/译者: ' + '/'.join(desc_list[0:-3])
except:
author_info='作者/译者: 暂无'
try:
pub_info = '出版信息: ' + '/'.join(desc_list[-3:])
except:
pub_info='出版信息: 暂无'
try:
rating = book_info.find('span', {'class':'rating_nums'}).string.strip()
except:
rating='0.0'
try:
people_num = book_info.findAll('span')[2].string.strip()
people_num=people_num.strip('人评价')
except:
people_num='0'
book_list.append([title,rating,people_num,author_info,pub_info])
try_times=0 #set 0 when got valid information
page_num+=1
print "Downloading Information From Page %d" % page_num
return book_list
def do_spider(book_tag_lists):
book_lists=[]
for book_tag in book_tag_lists:
book_list=book_spider(book_tag)
book_list=sorted(book_list,key=lambda x:x[1],reverse=True)
book_lists.append(book_list)
return book_lists
def print_book_lists_excel(book_lists,book_tag_lists):
wb=Workbook(optimized_write=True)
ws=[]
for i in range(len(book_tag_lists)):
ws.append(wb.create_sheet(title=book_tag_lists[i].decode())) #utf8->unicode
for i in range(len(book_tag_lists)):
ws[i].append(['序号','书名','评分','评价人数','作者','出版社'])
count=1
for bl in book_lists[i]:
ws[i].append([count,bl[0],float(bl[1]),int(bl[2]),bl[3],bl[4]])
count+=1
save_path='book_list'
for i in range(len(book_tag_lists)):
save_path+=('-'+book_tag_lists[i].decode())
save_path+='.xlsx'
wb.save(save_path)
if __name__=='__main__':
#book_tag_lists = ['心理','判断与决策','算法','数据结构','经济','历史']
#book_tag_lists = ['传记','哲学','编程','创业','理财','社会学','佛教']
#book_tag_lists=['思想','科技','科学','web','股票','爱情','两性']
book_tag_lists=['计算机','机器学习','linux','android','数据库','互联网']
book_lists=do_spider(book_tag_lists)
print_book_lists_excel(book_lists,book_tag_lists)
代码解析:
1、import
引入其他模块的代码,有两种引入的方式 一种是import xxx,另外一种是from xxx import yyy,第一种针对单个的文件,第二种针对包,第二种意思是从yyy包里引入xxx,python引入的模块有多种形式,可以是python脚本、dll文件等等,具体见: python import
2、reload()
当需要重新载入某个模块的时候,可以使用reload载入某个模块,如reload(sys)意思就是重新载入某个模块,意思是将之前导入的模块再加载一次,这样允许在不退出解释器的情况下重新加载已经更改的模块,不过一般不建议这样做。
2、def
def定义一个模块的变量或者类的变量,它本身是一个函数对象。如def aaa(): 就定义了一个叫做aaa()的函数
3、变量定义
count=1 这句话就定义了一个叫count的变量,并将其赋值为1,非常直观。
4、数组
python的数组分为三种类型:
list 普通的链表,初始化后可通过特定的方法动态增加元素
定义方式 arr=[元素]
Tuple固定的数据,一旦定义后不可改变:
定义方式:arr=(元素)
Dictionary类型的数组,即Hash数组,
定义方式 arr={k:v}
5、循环
python支持常用的所有循环,包括while,for等,
如while(1):代表无限循环,除非内部跳出,for循环为foreash形式,形如
for ele in elements:循环遍历elements里的所有元素
6、time模块
time模块为python内建模块,比如我们可以用time.sleep(seconds)让程序休眠一段时间
7、异常处理
python中的异常处理格式为:
try:
语句1
语句2
。。。
except a,b:
处理异常语句...
finally:
清理工作...
其中的a和b分别是异常类型和异常对象,值得注意的是这里的异常类型可以是多个,如下:
except (urllib2.HTTPError, urllib2.URLError), e:8、str()
将一个python的对象转化为对象,注意还有一个函数repr()也是这个功能,不过是它在转化为字符串之后还能转化为之前的对象
9、格式化输出
print "Downloading Information From Page %d" % page_num看起来是不是很熟悉 ,很类似c语言的风格,其实也很好理解,实用最多的还是c实现的python,当然和C会有一些借鉴
10、strip(xxx)
删除一个字符串首位的xxx字符,如果什么都不传就是删除首位的空格
11、sorted()
排序
11、open()
打开文件,open(name[,mode[,buffering]])
其中name表示需要打开的文件名字,mode是打开模式,第三个参数用来控制是否缓冲,默认是0表示不缓冲,1表示缓冲。
其中mode才是open()的灵魂,
- 参数 描述
- r 读取模式打开文件
- w 读写模式打开文件
- a 写入模式打开文件
- b 二进制模式打开文件(可以和其他模式并用)
- + 读/写模式(可以和其他模式并用)
- U 支持换行符(例如:\n、\r 或 \n\r 等)
- o=open('index.txt','w');
- o.write("大家好,欢迎光临坤子的博客(www.xuyukun.com)!")
- o.close();
上面的代表表示将字符串写入到index.txt文件中
12、__main__ __init__
在c/c++/java中main是程序执行 的起点,python中也有类似的运行机制,不过方式有所不同,python使用缩进对齐组织代码的执行,所有没有缩进的代码(非函数定义和类定义)都会在载入时自动执行,这些代码可以认为是python的main函数。
python引入__main__变量是为了区分主执行文件还是被调用的文件,当文件是被调用时,__name__的值是模块名字,当文件被直接执行时,__name__的值是__main__,这个特性为测试驱动的开发提供了极好的支持,我们可以在每个模块中写上测试代码,这些测试代码只有在python文件被直接执行的时候才会运行,代码和测试完美的结合在一起。
13、#!/usr/bin/env python 和 #!/usr/bin/python
首先这两行的作用都是为了在运行python文件的时候不需要用python xxx.py这种方式而是可以直接./xxx.py来运行,因为这个头指定了python解释器的位置。接下来说说这两者的区别:
通常认为#!/usr/bin/env python 要比 #!/usr/bin/python要好 因为有的时候python并不是安装在默认路径下面的,例如在virtualenv中。
而#!/usr/bin/python表示是写死了你要这个目录下的python来执行你的脚本,但通常这不是明智的选择。
这种写法在你机器上安装了多个版本的python的时候有意义,这样声明的时候,会去取你机器的 PATH 中指定的第一个 python 来执行你的脚本。如果这时候你又配置了虚拟环境的话,那么这样写可以保证脚本会使用你虚拟环境中的 python 来执行。
所以这样看来,只有第二种方法才是正确的写法。
14、openpyxl
python有好几个包都是用来处理excel的,比如xlrd xlwt xlutils,但是
- 它们都比较老,xlwt甚至不支持07版以后的excel
- 它们的文档不太友好,都可能需要去读源代码
15、range(xxx) 和len()函数
range由字面意思可见代表一个范围,
函数原型:range(start, end, scan):
先列几个range()函数的几个用法:
参数含义:start:计数从start开始。默认是从0开始。例如range(5)等价于range(0, 5);
end:技术到end结束,但不包括end.例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5
scan:每次跳跃的间距,默认为1。例如:range(0, 5) 等价于 range(0, 5, 1)
for i in range(5):
print i
i += 2
print i
print '一轮结束'
结果:
为什么不是下面的结果?
而不是:

len()
描述
Python len() 方法返回字符串、列表、字典、元组等长度
语法
len()方法语法:
len( xxx )
16、float()\int()
转化为float和int类型
17、None
None是一个特殊的常量。
None和False不同。
None不是0。
None不是空字符串。
None和任何其他的数据类型比较永远返回False。
None有自己的数据类型NoneType。
你可以将None复制给任何变量,但是你不能创建其他NoneType对象。
- >>> type(None)
- <class 'NoneType'>
- >>> None == 0
- False
- >>> None == ''
- False
- >>> None == None
- True
- >>> None == False
- False
None是一个空的对象,代表什么都没有
18、raw_input() 和 input()
两个都是读取用户输入不同点在于raw_input在处理输入时候总将输入作为字符串来处理,而input在遇到数字的时候会将其作为数字处理,如raw_input(3+4)返回字符串'3+4',input(3+4)返回7
而对于 input() ,它希望能够读取一个合法的 python 表达式,即你输入字符串的时候必须使用引号将它括起来,否则它会引发一个 SyntaxError
19、with。。。。as。。。。
简单的来说这个语法是用来代替传统的try。。。finally。。。语法的
with是从Python 2.5 引入的一个新的语法,更准确的说,是一种上下文的管理协议,用于简化try…except…finally的处理流程。with通过__enter__方法初始化,然后在__exit__中做善后以及处理异常。对于一些需要预先设置,事后要清理的一些任务,with提供了一种非常方便的表达。
在Python有2种方式来实现with语法:class-based和decorator-based,2种方式在原理上是等价的,可以根据具体场景自己选择
with最初起源于一种block…as…的语法,但是这种语法被很多人所唾弃,最后诞生了with,关于这段历史依然可以去参考PEP-343和PEP-340
20、yield
带有 yield 的函数在 Python 中被称之为 generator(生成器)
具体参考:http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/
---------------未完待续-------------
Python代码解析入门

这篇博客主要解析了Python的基础语法,包括import、reload()、def、变量定义、数组、循环、time模块、异常处理、格式化输出、strip()、sorted()、open()、__main__与__init__、文件头声明、openpyxl库、range()与len()函数、数据类型转换、None、raw_input()与input()、with...as...结构以及yield关键字,适合初学者了解Python编程。

589

被折叠的 条评论
为什么被折叠?



