文章目錄
  1. 1. 1.安装Python
  2. 2. 2.安装requests包
  3. 3. 一段爬虫代码:
  4. 4. 第二段爬虫代码:
  5. 5. 第三段爬虫代码:
  6. 6. 第四段爬虫代码:

这几天捡起之前没有看完的《Python核心编程》准备继续看,看了几章,发现又看不下去了,主要是书里全是理论,学着学着就不知道方向了,于是看了几集专门讲爬虫的视频,写了几个简单的爬虫,这里拿出来分享一下。
因为用到了requests模块,作为初学者,我还是把前后的安装过程也简单记录记录。

1.安装Python

这一步比较简单,直接去Python官网下载windows安装包安装(我的CentOS已经集成了Python,所以这里不讲Linux下了,一般的发行版也应该都自带了,直接在bash下输入python,然后回车,就可以看到)。因为目前商用比较流行的是Python2.7版,因此建议选择下载2.7版本。另外为了方便,建议直接安装到根目录下,比如D:\Python27,并且将此目录加入到Path环境变量,然后在命令行下输入python命令回车,如果显示了python版本号,则说明成功了,记得每次修改环境变量后,最好重启命令行。如果不成功,也没关系的,只是以后每次使用python命令都要在前面加上如D:\Python27\这个目录。

2.安装requests包

最直接的方法是下载requests包到本地,然后使用python setup.py install 命令安装。具体来讲就是进入requests官网,下载requests包,然后在D:\Python27\目录下新建一比如叫个modules的文件夹,放入其中。然后打开windows命令行,进入modules目录,再使用python setup.py install,就会看到开始安装。
不过为了以后安装其他包的方便,这里我们先安装setuptools包(官网解释其作用是“Easily download, build, install, upgrade, and uninstall Python packages”),以后就可以使用easy_install命令直接在线安装其他包。
以管理员模式打开windows命令行,输入Powershell回车,会发现提示符变成PS C:\WINDOWS\system32>,然后输入(Invoke-WebRequest https://bootstrap.pypa.io/ez_setup.py).Content | python - ,不出意外应该开始下载文件了,等下载并安装完成后,可以在D:\Python27\Scripts下看到easy_install.exe,我们可以将D:\Python27\Scripts加入环境变量,以后直接使用,这里我们可以输入easy_install pip 测试一下,( StackOverflow上建议我们在同时可以使用easy_install和pip命令时,最好使用pip)。
正式开始讲解爬虫部分。
关于requests包的常用命令,这里只讲解以下几个常用命令:

1
2
3
requests.get(url,data,headers),
requests.post(url,data,headers),
requests.session()

其中get()post()即对应HTTP两种请求的方式,url参数为必须的,其他参数可选,data是你想想在请求中携带的数据,比如登录信息,headers是伪装成浏览器发出请求。而session()作用是保持会话。

一段爬虫代码:


1
2
3
4
5
6
7
8
9
10
11
import requests
url = 'http://10.4.1.2/'
headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36' }
data = {'DDDDD':'2013210434',
'upass':'523410',
'mode':'0',
'0MKKey': }
s = requests.session()
response = s.post(url,data = form_data,headers = headers)
response.encoding = 'gb2312'
print response.text

这里是一段校园网登录代码,由于学校限制一个校园网只能同时有两个IP在线,而我一般宿舍一个,手机一个,来到教室后,电脑要上网的话,就必须先让宿舍的那个下线,很是麻烦,这段代码,由于没有IP就可以实现强制登录功能。
其中url是Chrome开发者工具中的Request URLheaders是Chrome开发者工具中Request Headers,一般只需要取User-Agent段,data是Chrome开发者工具中Form Data段的数据,这里要以字典形式列出,requests.session()则是保持会话功能,s.post(url,data = form_data,headers = headers)参数以元组格式列出返回一个respose对象,response.encoding 是设置变返回内容的编码属性,response.text属性是显示服务器返回的内容(注意和respose.content的区别,它是返回浏览器现实的HTML文档)。

第二段爬虫代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import requests
import os

i=1
print '本脚本可以帮助您筛选某个版面历史上人气最旺的部分帖子,并部分保存在本地,请按下面提示操作'+'\n'
board = raw_input('请直接输入您所选择查询的版面的英文完整名称,例如:"Python","StudyShare": ')
PAGE=int(raw_input('请输入您想查询的页数,一页代表最新的30篇帖子,为了爱护论坛的服务器,强烈建议您不要经常超过 10页(300篇啊): '))
REPLY=int(raw_input('请输入希望筛选回复数超过多少的帖子,为了爱护论坛的服务器,强烈建议您不要低于20: '))
ROW=30
bourl = "http://bbs.byr.cn/board/" + board +"?p="
filepath= 'bbs.byr.cn/article_ranklist/' + board +'/'

headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, compress',
'Accept-Language': 'en-us;q=0.5,en;q=0.3',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36' }

if os.path.exists(filepath):
pass
else:
os.makedirs(filepath)

if(int(PAGE)>=20):
PAGE=20

if(int(REPLY)<=20):
REPLY=20

while i <= PAGE:
bbourl = bourl + str(i)
print bbourl
print '--------------------------'
bbocont =requests.get(bbourl,headers=headers).content
ptrh = bbocont.find('<td class="title_8')
ptrt = bbocont.find(r'</td></tr>',ptrh)

articleurl = ['']*ROW
titlelist = ['']*ROW
replylist = ['']*ROW
j=0
while(ptrh!= -1 and ptrt!=-1 and j<=ROW):
ptitle_11htmp = bbocont.find(r'title_11 middle',ptrh)
ptitle_11h = bbocont.find(r'">',ptitle_11htmp)
ptitle_11t = bbocont.find(r'</td>', ptitle_11h)
replyamnt = bbocont[ ptitle_11h + len('">') : ptitle_11t ]
#print replyamnt

if(int(replyamnt)>=REPLY):
ptitle_9h = bbocont.find(r'<a href="',ptrh)
#print ptitle_9h
ptitle_9t = bbocont.find(r'">', ptitle_9h)
#print ptitle_9t
articleurl[j] = bbocont[ ptitle_9h + len('<a href="') : ptitle_9t ]
#print arturl
ptitlet = bbocont.find(r'</a>', ptitle_9t)
titlelist[j]= bbocont[ ptitle_9t + len('">') : ptitlet ]
replylist[j]=replyamnt

artipages = round((int(replylist[j])+1+5)/10)

artipaurltmp='http://bbs.byr.cn'+articleurl[j]+'?p='
n=1
while(n<=artipages):
artipaurl= artipaurltmp +str(n)
articont = requests.get(artipaurl,headers=headers).content
open(filepath+replylist[j]+'_'+titlelist[j]+'.html','a').write(artipaurl+'<br><br>')
print 'Downloading page: '+artipaurl
pcwh = articont.find(r'<div class="a-content-wrap">')
pcwt = articont.find(r'<font class=',pcwh)

NANU=10
k=0
namecont = articont[pcwh + len('<div class="a-content-wrap">') : pcwt]
while(pcwh!=-1 and pcwt!=-1 and namecont!=-1 and k<NANU):

open(filepath+replylist[j]+ '_' + titlelist[j] + '.html','a').write(namecont+'<br><br>')
pcwh = articont.find(r'<div class="a-content-wrap">',pcwt)
pcwt = articont.find(r'<font',pcwh)

namecont = articont[pcwh + len('<div class="a-content-wrap">') : pcwt]

k +=1

n +=1

ptrh = bbocont.find('<td class="title_8',ptrt)
ptrt = bbocont.find(r'</td></tr>',ptrh)

j +=1

i +=1
print 'Completed!'

这段代码功能是你指定论坛的一个版面,比如Python版,然后再指定一个回复数,再限定一个帖子总数,就可以把Python版最近的N个帖子中所有回复数超过某个数目的帖子找出来,并储存在本地。
虽然这里和前面比代码多了很多,但其实并不是很复杂,只是多了两个模块而已,一个是查找定位,另一个是文件读写。
以下面举例来说:

1
2
ptitle_11t = bbocont.find(r'</td>', ptitle_11h)
replyamnt = bbocont[ ptitle_11h + len('">') : ptitle_11t ]

其中bbocont.find()函数,第一个参数是要查找的内容,第二个参数可选,是查找的位置,返回一个整数,表示查找的第一个字符位于文件中的位置,
bbocont[ ptitle_11h + len(‘“>’) : ptitle_11t]是依据两个位置参数截取这两个位置间文档的内容,并返回。
第二个部分是:

1
2
3
4
5
6
7
8
9
10
if os.path.exists(filepath):
pass
else:
os.makedirs(filepath)
```

这里是在当前目录下新建一个多级目录,注意<code>os.mkdir("file")</code>是新建目录,而不能创建多级目录

```python
open(filepath+replylist[j]+'_'+titlelist[j]+'.html','a').write(artipaurl+'<br><br>')

则是打开指定目录,a代表以追加方式打开,write()里的参数是写入文件的内容。
另外header中加入的‘X-Requested-With’:’XMLHttpRequest’,是由于论坛的Ajax响应方式需要额外添加的。
下面是另外两段类似的爬虫脚本:

第三段爬虫代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import requests
import os

i=1
print '本脚本可以帮助您筛选某个版面历史上部分有特殊标记的精华帖子,并部分保存在本地,请按下面提示操作'+'\n'
board = raw_input('请直接输入您所选择查询的版面的英文完整名称,例如:"Python","StudyShare": ')
PAGE=int(raw_input('请输入您想查询的页数,一页代表最新的30篇帖子,为了爱护论坛的服务器,强烈建议您不要经常超过 10页(300篇啊): '))
ROW=30

bourl = "http://bbs.byr.cn/board/" + board +"?p="
filepath= 'bbs.byr.cn/tag_list/' + board +'/'

headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, compress',
'Accept-Language': 'en-us;q=0.5,en;q=0.3',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',

'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36' }

if os.path.exists(filepath):
pass
else:
os.makedirs(filepath)

if(int(PAGE)>=50):
#PAGE=50



while (i <= PAGE) :
bbourl = bourl + str(i)
print bbourl
print '--------------------------'
bbocont =requests.get(bbourl,headers=headers).content


articleurl = ['']*ROW
titlelist = ['']*ROW
taglist = ['']*ROW
replylist =['']*ROW
j=0

ptitle_8h = bbocont.find('<td class="title_8')
ptitle_8t = bbocont.find(r'</samp>',ptitle_8h)


while(ptitle_8h!= -1 and ptitle_8t!=-1 and j<=ROW):
psamph = bbocont.find(r'<samp class="tag',ptitle_8h)
psampt = bbocont.find(r'"></samp>',psamph)
tagcont = bbocont[ psamph + len(r'<samp class="tag ico-pos-article-') : psampt ]
#print tagcont

ptitle_11htmp = bbocont.find(r'title_11 middle', ptitle_8h)
ptitle_11h = bbocont.find(r'">',ptitle_11htmp)
#print ptitle_11h
ptitle_11t = bbocont.find(r'</td>', ptitle_11h)
#print ptitle_11t
replyamnt = bbocont[ ptitle_11h + len('">') : ptitle_11t ]



if(tagcont=='b' or tagcont=='m' or tagcont=='g' or tagcont=='fire'):
particleurlh = bbocont.find(r'<a target="_blank" href="',ptitle_8h )
#print particleurlh
particleurlt = bbocont.find(r'" title', particleurlh)
#print particleurlt
articleurl[j] = bbocont[ particleurlh + len('<a target="_blank" href="') : particleurlt ]

ptitlehtmp = bbocont.find(r'<a href="', psampt)
ptitleh = bbocont.find(r'">', ptitlehtmp)
ptitlet = bbocont.find(r'</a>', ptitleh)
titlelist[j]= bbocont[ ptitleh + len('">') : ptitlet ]
replylist[j]=replyamnt

if(tagcont=='b'):
taglist[j]="金钻"
if(tagcont=='m'):
taglist[j]="黄钻"
if(tagcont=='g'):
taglist[j]="蓝钻"
if(tagcont=='fire'):
taglist[j]="火钻"





artipages = round((int(replylist[j])+1+5)/10)

artipaurltmp='http://bbs.byr.cn'+articleurl[j]+'?p='
n=1
while(n<=artipages):
artipaurl= artipaurltmp +str(n)
articont = requests.get(artipaurl,headers=headers).content
open(filepath+taglist[j]+replylist[j]+'_'+titlelist[j]+'.html','a').write(artipaurl+'<br><br>')
print 'Downloading page: '+taglist[j]+artipaurl
pcwh = articont.find(r'<div class="a-content-wrap">')
pcwt = articont.find(r'<font class=',pcwh)

NANU=10
k=0
namecont = articont[pcwh + len('<div class="a-content-wrap">') : pcwt]
while(pcwh!=-1 and pcwt!=-1 and namecont!=-1 and k<NANU):

open(filepath+taglist[j]+replylist[j]+ '_' + titlelist[j] + '.html','a').write(namecont+'<br><br>')
pcwh = articont.find(r'<div class="a-content-wrap">',pcwt)
pcwt = articont.find(r'<font',pcwh)

namecont = articont[pcwh + len('<div class="a-content-wrap">') : pcwt]

k +=1


n +=1

ptitle_8h = bbocont.find('<td class="title_8',ptitle_8t)
ptitle_8t = bbocont.find(r'</samp>',ptitle_8h)

j +=1
i +=1
print 'Completed!'

第四段爬虫代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import requests
import os

print '本脚本可以帮助您查找出某个版面历史上某个id参与过的帖子,并保存在本地查看,请按下面提示操作'+'\n'

userid=raw_input('请直接输入您想查询的用户id: ')
board = raw_input('请直接输入您所选择查询的版面的英文完整名称,例如:"Python","StudyShare","WorkLife": ')
PAGE = int(raw_input('请输入您想查询的页数,一页代表最新的30篇帖子,为了爱护论坛的服务器,强烈建议您不要经常超过 10页(300篇啊): '))

bourl = "http://bbs.byr.cn/board/" + board +"?p="
filepath= 'bbs.byr.cn/id_list/' + userid+'/' + board +'/'

headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, compress',
'Accept-Language': 'en-us;q=0.5,en;q=0.3',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',

'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36' }

if os.path.exists(filepath):
pass
else:
os.makedirs(filepath)

if(PAGE>=50):
PAGE=50


i=1
ROW=30

while (i <= PAGE):
bbourl = bourl + str(i)
print bbourl
print '--------------------------'
bbocont =requests.get(bbourl,headers=headers).content


ptitle_8h = bbocont.find('<td class="title_8')
ptitle_8t = bbocont.find(r'</samp>',ptitle_8h)

articleurl = ['']*ROW
titlelist = ['']*ROW
replylist = ['']*ROW
authorlist = ['']*ROW
j=0
while(ptitle_8h != -1 and ptitle_8t !=-1 and j<=ROW):

psamph = bbocont.find(r'<samp class="tag',ptitle_8h)
psampt = bbocont.find(r'"></samp>',psamph)
tagcont = bbocont[ psamph + len(r'<samp class="tag ico-pos-article-') : psampt ]
#print tagcont

ptitle_11htmp = bbocont.find(r'title_11 middle', ptitle_8h)
ptitle_11h = bbocont.find(r'">',ptitle_11htmp)
#print ptitle_11h
ptitle_11t = bbocont.find(r'</td>', ptitle_11h)
#print ptitle_11t
replyamnt = bbocont[ ptitle_11h + len('">') : ptitle_11t ]

if(1):
particleurlh = bbocont.find(r'<a target="_blank" href="',ptitle_8h )
#print particleurlh
particleurlt = bbocont.find(r'" title', particleurlh)
#print particleurlt
articleurl[j] = bbocont[ particleurlh + len('<a target="_blank" href="') : particleurlt ]

ptitlehtmp = bbocont.find(r'<a href="', psampt)
ptitleh = bbocont.find(r'">', ptitlehtmp)
ptitlet = bbocont.find(r'</a>', ptitleh)
titlelist[j]= bbocont[ ptitleh + len('">') : ptitlet ]

pauthorhtmp1 = bbocont.find(r'<td class="title_12', psampt)
pauthorhtmp2 = bbocont.find(r'<a href', pauthorhtmp1)
pauthorh = bbocont.find(r'">', pauthorhtmp2)
pauthort = bbocont.find(r'</a>', pauthorh)
authorlist[j]= bbocont[ pauthorh + len('">') : pauthort ]
#print authorlist[j]

replylist[j]=replyamnt
artipages = int(round((int(replylist[j])+1+5)/10))
#print artipages
artipaurltmp = 'http://bbs.byr.cn'+articleurl[j]+'?p='
n=1
flag=0
while(flag == 0 and n <= artipages):

artipaurl= artipaurltmp +str(n)
#print artipaurl
articont = requests.get(artipaurl,headers=headers).content

puidhtmp1 = articont.find(r'<span class="a-u-name"><a href="')
puidhtmp2 = articont.find(r'<a href=',puidhtmp1)
puidh = articont.find(r'">',puidhtmp2)
puidt = articont.find(r'</a>',puidh)
uidcont = articont[puidh + len('">') : puidt]
#print uidcont

NANU=10
k=0

while(puidh!=-1 and puidt!=-1 and uidcont!=-1 and k<NANU):
#print uidcont
if(uidcont==userid):
#print flag
flag = 1
#print flag
n=0
print 'Downloading page: '+userid+'-'+artipaurltmp+'1'
break

puidhtmp1 = articont.find(r'<span class="a-u-name"><a href="',puidt)
puidhtmp2 = articont.find(r'<a href=',puidhtmp1)
puidh = articont.find(r'">',puidhtmp2)
puidt = articont.find(r'</a>',puidh)
uidcont = articont[puidh + len('">') : puidt]

k +=1

n +=1

while(flag==1 and n<=artipages):

artipaurl= artipaurltmp +str(n)
articont = requests.get(artipaurl,headers=headers).content
try:
open(filepath+replylist[j]+ '_'+'id'+' '+authorlist[j]+'_' + titlelist[j] + '.html','a').write(artipaurl+'<br><br>')
except IOError:
pass
#print 'Downloading page: '+userid+'-'+artipaurl
pcwh = articont.find(r'<div class="a-content-wrap">')
pcwt = articont.find(r'<font class=',pcwh)

NANU=10
k=0
namecont = articont[pcwh + len('<div class="a-content-wrap">') : pcwt]
while(pcwh!=-1 and pcwt!=-1 and namecont!=-1 and k<NANU):
try:
open(filepath+replylist[j]+ '_'+'id'+' '+authorlist[j]+'_' + titlelist[j] + '.html','a').write(namecont+'<br><br>')
except IOError:
pass

#print 'Downloaded page: '+userid+' '+artipaurl
pcwh = articont.find(r'<div class="a-content-wrap">',pcwt)
pcwt = articont.find(r'<font',pcwh)

namecont = articont[pcwh + len('<div class="a-content-wrap">') : pcwt]

k +=1


n +=1


ptitle_8h = bbocont.find('<td class="title_8',ptitle_8t)
ptitle_8t = bbocont.find(r'</samp>',ptitle_8h)

j +=1

i +=1
print 'Completed!'

希望后期能够把这几个实用的小爬虫优化一下,比如整理成函数,增加按section查询的功能,并且优化输出文本的CSS,采用XPath或者CSS选择器来查找等等。


扩展阅读:
1.Requests中文文档
2.python requests的安装与简单运用

文章目錄
  1. 1. 1.安装Python
  2. 2. 2.安装requests包
  3. 3. 一段爬虫代码:
  4. 4. 第二段爬虫代码:
  5. 5. 第三段爬虫代码:
  6. 6. 第四段爬虫代码: