Python爬取本博客首页与调试

最近想抓一点其他网站的内容,但是用PHP做感觉有点奇怪,单纯用正则表达式也比较不便。于是狠补了下Python的内容,虽然基本原理都是下载->分析->提取->存储,但Python里面的3方包等工具还是相对健全很多,如BeautifulSoup就十分好用。


简单爬虫

写的尽量简单点,用到re,BeautifulSoup,urllib2等模块。不包含URL管理器等。

博客页面分析

以抓取本博客http://blog.xigulu.com/为例。提取出首页标题及摘要内容,最后将提取的内容写入html。

审查网页源码,可以发现:
标题部分:

1
2
3
4
5
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2016/05/12/php_route_url_pretty/" itemprop="url">
PHP单一入口模式及URL路由美化
</a>
</h1>

摘要部分:

1
2
3
4
5
6
7
8
<div class="post-body" itemprop="articleBody">
<p>大部分PHP框架都是基于单一入口模式,如yii,ci,slim等框架中都有实现,且配置都非常简单。最近想把自己以前写的一个零散的项目整理成单一入口模式,于是研究了下,实现了基本可用的功能。包括URL路由,美化功能。</p>
<div class="post-more-link text-center">
<a class="btn" href="/2016/05/12/php_route_url_pretty/#more" rel="contents">
阅读全文 »
</a>
</div>
</div>

爬取过程:

  • 先使用urllib2下载网页
  • 分析下载的网页,使用BeautifulSoup + 正则 提取想要的内容
  • 输出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
#coding=utf-8
#抓取http://blog.xigulu.com/首页的标题及摘要内容
import bs4
import re
import urllib2
from bs4 import BeautifulSoup
class MySpider:
#下载html
def download_html(self,url):
print "start download_html:"
response = urllib2.urlopen(url)
if response.getcode() != 200:
return None
print "finish download_html!"
return response.read()
#解析html
def parser_html(self,html_str):
print "start parser_html:"
result_list = [] #结果存放到list中, list元素为字典
soup = BeautifulSoup(html_str, "html.parser", from_encoding="utf-8")
'''
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2016/05/12/php_route_url_pretty/" itemprop="url">
PHP单一入口模式及URL路由美化
</a>
</h1>
'''
#title_nodes = soup.find_all('a', class_="post-title-link")
title_nodes = soup.select("h1.post-title a.post-title-link")
'''
<div class="post-body" itemprop="articleBody">
<p>大部分PHP框架都是基于单一入口模式,如yii,ci,slim等框架中都有实现,且配置都非常简单。最近想把自己以前写的一个零散的项目整理成单一入口模式,于是研究了下,实现了基本可用的功能。包括URL路由,美化功能。</p>
<div class="post-more-link text-center">
<a class="btn" href="/2016/05/12/php_route_url_pretty/#more" rel="contents">
阅读全文 »
</a>
</div>
</div>
'''
#summary_nodes = soup.find_all('div', class_="post-body")
summary_nodes = soup.select("div.post-body p") #这里通过select来操作, 比find方法更好
#下载的html中, 几个p标签未闭合. 导致带上了" 阅读全文 »"
for index in range(len(title_nodes)):
result_data = {}
result_data['title'] = title_nodes[index].get_text()
result_data['summary'] = summary_nodes[index].get_text()
#result_data['summary'] = summary_nodes[index].find('p').get_text()
result_list.append(result_data)
print "finish parser_html!"
return result_list
#结果存为htnl展示
def save2html(self,list_data):
out_html = open('output.html', 'w')
print "start save2html:"
out_html.write("<html>")
out_html.write("<table style='border:1px solid #000'>")
for data in list_data:
out_html.write("<tr>")
out_html.write("<td style='border:1px solid #000'>%s</td>" % data['title'].encode('utf8'))
out_html.write("<td style='border:1px solid #000'>%s</td>" % data['summary'].encode('utf8'))
out_html.write("</tr>")
out_html.write("</table>")
out_html.write("</html>")
out_html.close()
print "finish save2html!"
#测试
if __name__ == "__main__":
mysapider = MySpider()
url = "http://blog.xigulu.com/"
html_str = mysapider.download_html(url)
#print html_str
list_data = mysapider.parser_html(html_str)
mysapider.save2html(list_data)

说明见注释。

调试类

出于经常需要调试与输出数据,于是写了个简单的调试类。(复杂一点的还是用PyDev或PyCharm集成开发环境调试更好)

直接贴代码:

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
#coding=utf-8
from ipdb import set_trace
class XNDebug:
#is 与 == 的区别就是is根据id, ==根据值 判断.
def __init__(self):
self.debugStatus = True #False
#打印list
def logList(self,varlist):
if self.debugStatus != True:
return
if varlist is None or not varlist:
print "logList--> is None"
elif type(varlist) == list:
for index in range(len(varlist)):
print "logList[%d]-->%s"%(index,varlist[index])
else:
print "logList--> not list type!"
#打印字典
def logDict(self,varDict):
if self.debugStatus != True:
return
if varDict is None or not varDict:
print "varDict--> is None"
elif type(varDict) == dict:
for (k, v) in varDict.items():
print 'logDict->%s:%s !' % (k, v)
else:
print "logDict--> not dict type!"
#打印set (不重复, 无序的. 只是这个无序, 没必要标号)
def logSet(self,varSet):
if self.debugStatus != True:
return
if varSet is None or not varSet:
print "varSet--> is None"
elif type(varSet) == set:
for setItem in varSet:
print "varSet-->",setItem
else:
print "varSet--> not set type!"
#写入到html文件(存长文本 )
def save2html(self,varParam):
if self.debugStatus != True:
return
if varParam is None or not varParam:
print "save2html:varParam--> is None"
return
#写入html
out_html = open('out.html', 'w')
out_html.write("<html>")
out_html.write("<body>")
out_html.write("%s" % varParam.encode('utf8'))
out_html.write("</body>")
out_html.write("</html>")
out_html.close()
#在该地方使用ipdb调试. (使用"p 变量名"可以查看变量的值, n执行下一行)
def debug_ipdb(self):
if self.debugStatus != True:
return
set_trace()
#测试
if __name__ == "__main__":
xndebugObj = XNDebug()
mylist = ['a','b','c']
xndebugObj.logList(mylist)
mydict = {}
mydict1 = {'a':123,'b':'sss'}
xndebugObj.logDict(mydict1)
#存长文本
testStr= "write this string"
xndebugObj.save2html(testStr)
xndebugObj.debug_ipdb()
myset = set('http') #初始化时为拆分成单个元素
abc = "12133333" #这样是作为一个整体的
myset.add(abc)
xndebugObj.logSet(myset)

其中debug_ipdb方法中使用了ipdb调试,直接在控制台运行,十分方便。

结语

以上使用的beautifulsoup4,ipdb为第三库,安装使用“pip install xxx”即可。

转载请注明出处,有疑问欢迎留言!