python爬虫Pragmatic系列III
By 白熊花田(http://blog.csdn.net/whiterbear)
说明:
在上一篇博客中,我们已经学会了从赶集网上的一家公司中提取出有关的信息,并存储到Excel中。
本次目标:
在本节中,我们将批量下载赶集首页上所有的公司界面(注意不是赶集网上所有的公司页面,我们可以把这个留给之后的任务),并批量的处理所有公司的有关信息,并保存到Excel中。
注意:
在上一篇博客中,我们使用的只是匹配赶集网上其中一家公司界面的中信息,而且不幸的是,很多的其他的公司的联系店主模块中的信息数量并不是固定的,即有的是10个li,而有的是9个li或者12个li,而且并不是所有公司都提供了QQ联系方式或者公司名称。所以,我对代码稍微做了处理,使其能够适应大部分的网页。
批量下载网页:
如下图:
我们将提取出该网页所包含的公司链接,并批量下载下来。这次,我们使用了一个下载类,利用下载类来封装我们所要的方法。我们先给定赶集网的首页链接,下载首页,接着我们分析出首页包含的公司链接并保存起来,最后我们将这些链接都下载到pagestroage文件夹中。
代码:
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 1#-*-coding:utf-8-*-
2import re
3import os
4from urllib import urlretrieve
5from bs4 import BeautifulSoup
6
7
8class Download(object):
9 '该类将包含下载给定的url和将其保存\
10 为相应的文件的方法'
11 def __init__(self):
12 self.index = 0
13 #初始化
14
15 def getPages(self,url,isMain=False):
16 '根据给定的url进行下载,如果是赶集网主界面,则另行处理'
17 for u in url:
18 try:
19 revtal = urlretrieve(u)[0]
20 except IOError:
21 revtal = None
22 if revtal <> None and isMain == True:
23 #是赶集网主界面
24 self.savePages(revtal, isMain=True)
25 elif revtal <> None and isMain <> True:
26 self.savePages(revtal)
27 else:
28 print('Open url error')
29
30 def savePages(self,webpage,isMain=False):
31 '将给定的网页保存起来'
32 f = open(webpage)
33 lines = f.readlines()
34 f.close()
35
36 if isMain == False:
37 #不是主界面则按序存储为filei.txt,i为序号
38 fobj = open("pagestroage\\file%s.txt"%str(self.index), 'w')
39 self.index += 1
40 fobj.writelines(lines)
41 else:
42 #是赶集网主界面,则存储为mian.txt
43 fobj = open("pagestroage\main.txt",'w')
44 fobj.writelines(lines)
45
46 fobj.close()
47
48
49 def getAllComUrls(self):
50 '我们对赶集网的主界面进行分析,提取出所有公司的链接,保存起来'
51 if os.path.exists('pagestroage\main.txt'): #判断文件是否存在
52 fobj = open('pagestroage\main.txt','r')
53 lines = fobj.readlines()
54 fobj.close()
55
56 soup = BeautifulSoup(''.join(lines))
57 body = soup.body
58 #wrapper = soup.find(id="wrapper")
59 leftBox = soup.find(attrs={'class':'leftBox'})
60 list_ = leftBox.find(attrs={'class':'list'})
61 ul = list_.find('ul')
62 li = ul.find_all('li')
63 href_regex = r'href="(.*?)"'
64 urls = []
65
66 for l in li:
67 urls.append('http://bj.ganji.com' + re.search(href_regex,str(l)).group(1))
68 #print urls
69
70 return urls
71 else:
72 print('The file is missing')
73 return None
74
75
76if __name__ == '__main__':
77 #初试设定url为赶集网首页
78 url=['http://bj.ganji.com/danbaobaoxian/o1/']
79 #实例化下载类
80 download = Download()
81 #先下载赶集网首页
82 download.getPages(url,True)
83 #对下载的赶集网首页信息进行分析,提取出所有公司的url
84 urls = download.getAllComUrls()
85 #对上面提取的url进行下载
86 download.getPages(urls)
87
运行结果:
我们得到了十几个包含公司网页的文本文件。如下图:
分析网页:
由上面的操作,我们已经得到了赶集网上所有公司的html文本。接着我们使用Analysiser类来处理我们得到的数据。注意,Analysiser类中的方法基本上都在前面的博客中介绍了,这里只是用类封装了,并使其能够批量处理。
代码:
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181 1#-*-coding:utf-8-*-
2import re
3from bs4 import BeautifulSoup
4import xlwt
5import os
6import sys
7reload(sys)
8sys.setdefaultencoding('utf-8')
9
10class Analysiser(object):
11 '该类将分析下载的公司信息存储到Excel表格中'
12 def __init__(self):
13 '初始化一个Excel'
14 self.wb = xlwt.Workbook()
15 self.ws = self.wb.add_sheet('CompanyInfoSheet')
16 self.initExcel()
17
18 def initExcel(self):
19 '我们初试化一个表格,并给表格一个头部,所以我们给头部不一样的字体'
20 #初始化样式
21 style = xlwt.XFStyle()
22 #为样式创建字体
23 font = xlwt.Font()
24 font.name = 'Times New Roman'
25 font.bold = True
26 #为样式设置字体
27 style.font = font
28
29 # 使用样式
30 #写入公司名称
31 self.ws.write(0,0,u'公司名称', style)
32 #写入服务特色
33 self.ws.write(0,1,u'服务特色', style)
34 #写入服务范围
35 self.ws.write(0,2,u'服务范围', style)
36 #写入联系人
37 self.ws.write(0,3,u'联系人', style)
38 #写入商家地址
39 self.ws.write(0,4,u'商家地址', style)
40 #写入聊天QQ
41 self.ws.write(0,5,u'QQ', style)
42 #写入联系电话
43 self.ws.write(0,6,u'联系电话', style)
44 #写入网址
45 self.ws.write(0,7,u'公司网址', style)
46 self.wb.save('xinrui.xls')
47
48 def analysAllFiles(self):
49 '''
50 批量分析网页源码,并提取出公司相关信息
51 '''
52 #得到pagestroage(我们存放下载的公司网页的文件夹)下所有的文件
53 filenames = os.listdir('pagestroage')
54 #得到所有存储的公司数目(去除一个包含赶集网首页的main.txt)
55 counts = len(filenames) - 1
56 #循环处理
57 for i in range(counts):
58 #打开文件,读文件到lines中,关闭文件对象
59 f = open("pagestroage\\file%s.txt"%i, 'r')
60 lines = f.readlines()
61 f.close()
62
63 #这两个网页的联系店主模块与其他的不一样,如果也要匹配只能重新写代码匹配,遂放弃
64 if i == 12 or i == 7:
65 continue
66
67 #建立一个BeautifulSoup解析树,并利用这课解析树依次按照
68 #soup-->body-->(id为wrapper的div层)-->(class属性为clearfix的div层)
69 #-->(id为dzcontactus的div层)-->(class属性为con的div层)-->ul-->(ul下的每个li)
70 soup = BeautifulSoup(''.join(lines))
71 body = soup.body #body2 = soup.find('body')
72 wrapper = soup.find(id="wrapper")
73 clearfix = wrapper.find_all(attrs={'class':'d-left-box'})[0]
74 dzcontactus = clearfix.find(id="dzcontactus")
75 con = dzcontactus.find(attrs={'class':'con'})
76 ul = con.find('ul')
77 li = ul.find_all('li')
78
79 #记录一家公司的所有信息,用字典存储,可以依靠键值对存取,也可以换成列表存储
80 record = {}
81
82 #公司名称
83 companyName = li[1].find('h1').contents[0]
84 record['companyName'] = companyName
85
86 #服务特色
87 serviceFeature = li[2].find('p').contents[0]
88 record['serviceFeature'] = serviceFeature
89
90 #服务提供
91 serviceProvider = []
92 serviceProviderResultSet = li[3].find_all('a')
93 for service in serviceProviderResultSet:
94 serviceProvider.append(service.contents[0])
95
96 record['serviceProvider'] = serviceProvider
97
98 #服务范围
99 serviceScope = []
100 serviceScopeResultSet = li[4].find_all('a')
101 for scope in serviceScopeResultSet:
102 serviceScope.append(scope.contents[0])
103
104 record['serviceScope'] = serviceScope
105
106 #联系人
107 contacts = li[5].find('p').contents[0]
108 contacts = str(contacts).strip().encode("utf-8")
109 record['contacts'] = contacts
110
111 #商家地址
112 addressResultSet = li[6].find('p')
113 re_h=re.compile('</?\w+[^>]*>')#HTML标签
114 address = re_h.sub('', str(addressResultSet))
115 record['address'] = address.encode("utf-8")
116
117 restli = ''
118 for l in range(8,len(li) - 1):
119 restli += str(li[l])
120
121 #商家QQ
122 qqNumResultSet = restli
123 qq_regex = '(\d{5,10})'
124 qqNum = re.search(qq_regex,qqNumResultSet).group()
125 qqNum = qqNum
126 record['qqNum'] = qqNum
127
128 #联系电话
129 phone_regex= '1[3|5|7|8|][0-9]{9}'
130 phoneNum = re.search(phone_regex,restli).group()
131 record['phoneNum'] = phoneNum
132
133 #公司网址
134 companySite = li[len(li) - 1].find('a').contents[0]
135 record['companySite'] = companySite
136
137 self.writeToExcel(record,i + 1)
138
139 def writeToExcel(self,record,index):
140 '该函数将给定的record字典中所有值存储到Excel相应的index行中'
141 #写入公司名称
142 companyName = record['companyName']
143 self.ws.write(index,0,companyName)
144
145 #写入服务特色
146 serviceFeature = record['serviceFeature']
147 self.ws.write(index,1,serviceFeature)
148
149 #写入服务范围
150 serviceScope = ','.join(record['serviceScope'])
151 self.ws.write(index,2,serviceScope)
152
153 #写入联系人
154 contacts = record['contacts']
155 self.ws.write(index,3,contacts.decode("utf-8"))
156
157 #写入商家地址
158 address = record['address']
159 self.ws.write(index,4,address.decode("utf-8"))
160
161 #写入聊天QQ
162 qqNum = record['qqNum']
163 self.ws.write(index,5,qqNum)
164
165 #写入联系电话
166 phoneNum = record['phoneNum']
167 phoneNum = str(phoneNum).encode("utf-8")
168 self.ws.write(index,6,phoneNum.decode("utf-8"))
169
170 #写入网址
171 companySite = record['companySite']
172 self.ws.write(index,7,companySite)
173 self.wb.save('xinrui.xls')
174
175if __name__ == '__main__':
176 ana = Analysiser()
177 ana.analysAllFiles()
178
179
180
181
运行结果:
我们将得到包含赶集网首页上包含的所有公司的相关信息的Excel,如下图:
后感:
看到这个Excel是不觉得很cool,终于能做点实际的事情了。
不过,我们还可以做的更好,更智能。
未完待续。