首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Python 爬虫:Beautiful Soup 实例(一)

一次性付费进群,长期免费索取教程,没有付费教程。

教程列表见微信公众号底部菜单 |本文底部有推荐书籍

微信公众号:计算机与网络安全

ID:Computer-network

经常在网上追剧,偶尔也在百度贴吧上看看美剧贴,可又比较懒,天天登录贴吧查看贴子觉得很麻烦。干脆就写个爬虫让它自动爬内容好了,有空就看看哪些帖子回复了,又有哪些新贴。这里以百度贴吧里的“权利的游戏吧”为例。

1、目标分析

图1 编码转换

在浏览器(这里使用的是Chrome浏览器,其他浏览器基本上都差不多)中打开这个URL,查看帖子标题,如图2所示。

图2 bs4爬虫来源页面

图3 所需数据位置

找到所需数据的位置后,仔细观察一下,发现所有帖子都有一个共同的标签

(这个标签还有其他的属性,只需要一个共同的属性就够了)。所以只需要用bs4过滤器find_all找到所有的标签,然后再进一步分离出所需的数据就可以了。

2、项目实施

既然思路都已经明确了,那就开工吧。打开Eclipse,单击New图标右侧的三角按钮,在弹出菜单中选择PyDev Project项,如图4所示。

图4 Eclipse创建Python新项目

在弹出的对话框中输入项目名称,单击Finish按钮,如图5所示。

图5 输入项目名

图6 在项目中创建Python文件

图7 Python文件名

1 #!/usr/bin/evn python3

2 #-*- coding: utf-8 -*-

3 '''

4 Created on 2016年8月9日

5

7 '''

8

9

10 import urllib.request

11 import urllib.parse

12 from bs4 import BeautifulSoup

13 from mylog import MyLog as mylog

14 import codecs

15

16

17 class Item(object):

18 title = None #帖子标题

19 firstAuthor = None #帖子创建者

20 firstTime = None #帖子创建时间

21 reNum = None #总回复数

22 content = None #最后回复内容

23 lastAuthor = None #最后回复者

24 lastTime = None #最后回复时间

25

26

27 class GetTiebaInfo(object):

28 def __init__(self,url):

29 self.url = url

30 self.log = mylog()

31 self.pageSum = 5

32 self.urls = self.getUrls(self.pageSum)

33 self.items = self.spider(self.urls)

34 self.pipelines(self.items)

35

36 def getUrls(self,pageSum):

37 urls = []

38 pns = [str(i*50) for i in range(pageSum)]

40 for pn in pns:

41 ul[-1] = pn

42 url = '='.join(ul)

43 urls.append(url)

45 return urls

46

47 def spider(self, urls):

48 items = []

49 for url in urls:

50 htmlContent = self.getResponseContent(url)

51 soup = BeautifulSoup(htmlContent, 'lxml')

52 tagsli = soup.find_all('li',attrs={'class':' j_thread_listclearfix'})

53 for tag in tagsli:

54 item = Item()

55 item.title = tag.find('a',attrs={'class':'j_th_tit'}).get_text().strip()

56 item.firstAuthor = tag.find('span', attrs={'class':'frs-author-name-wrap'}).a.get_text().strip()

57 item.firstTime = tag.find('span', attrs={'title':'创建时间'}).get_text().strip()

58 item.reNum = tag.find('span', attrs={'title':'回复'}).get_text().strip()

59 item.content = tag.find('div',attrs={'class':'threadlist_abs threadlist_abs_onlyline '}).get_text().strip()

60 item.lastAuthor = tag.find('span',attrs={'class':'tb_icon_author_rely j_replyer'}).a.get_text().strip()

61 item.lastTime = tag.find('span', attrs={'title':'最后回复时间'}).get_text().strip()

62 items.append(item)

64 return items

65

66 def pipelines(self, items):

67 fileName = '百度贴吧_权利的游戏.txt'#.encode('utf-8')

68 with codecs.open(fileName, 'w', 'utf-8') as fp:

69 for item in items:

70 try:

71 fp.write('title:%s \t author:%s \t firstTime:%s \r\ncontent:%s \r\n return:%s \r\n lastAuthor:%s \t lastTime:%s \r\n\r\n\r\n\r\n'

72 %(item.title, item.firstAuthor, item.firstTime,item.content, item.reNum, item.lastAuthor, item.lastTime))

73 except Exception as e:

75 else:

77

78 def getResponseContent(self, url):

79 '''这里单独使用一个函数返回页面返回值,是为了后期方便的加入proxy和headers等

80 '''

81 urlList = url.split('=')

83 url = '='.join(urlList)

84 try:

86 except:

88 else:

90 return response.read()

91

92

93 if __name__ == '__main__':

95 GTI = GetTiebaInfo(url)

按照上面的步骤,在项目中重新建立一个名为mylog.py的PyDev Module(也可以是一个单纯的File)。

mylog.py的内容如下:

1 #!/usr/bin/env python3

2 # -*- coding:utf-8 -*-

3 #Author :hstking

5 #Ctime :2015/09/15

6 #Mtime :

7 #Version :

8

9 import logging

10 import getpass

11 import sys

12

13

14 #### 定义MyLog类

15 class MyLog(object):

16 #### 类MyLog的构造函数

17 def __init__(self):

18 self.user = getpass.getuser()

19 self.logger = logging.getLogger(self.user)

21

22 #### 日志文件名

23 self.logFile = sys.argv[0][0:-3] + '.log'

24 self.formatter = logging.Formatter('%(asctime)-12s %(levelname)-8s %(name)-10s %(message)-12s\r\n')

25

26 #### 日志显示到屏幕上并输出到日志文件内

27 self.logHand = logging.FileHandler(self.logFile, encoding='utf8')

28 self.logHand.setFormatter(self.formatter)

29 self.logHand.setLevel(logging.DEBUG)

30

31 self.logHandSt = logging.StreamHandler()

32 self.logHandSt.setFormatter(self.formatter)

33 self.logHandSt.setLevel(logging.DEBUG)

34

37

38 #### 日志的5个级别对应以下的5个函数

39 def debug(self,msg):

41

42 def info(self,msg):

44

45 def warn(self,msg):

47

48 def error(self,msg):

50

51 def critical(self,msg):

53

54 if __name__ == '__main__':

55 mylog = MyLog()

56 mylog.debug(u"I'm debug 测试中文")

57 mylog.info("I'm info")

58 mylog.warn("I'm warn")

59 mylog.error(u"I'm error 测试中文")

60 mylog.critical("I'm critical")

项目代码已经完成了。此时Eclipse中的项目如图8所示。

图8 Eclipse项目baiduBS4

单击菜单栏上的运行图标,程序运行完毕后单击baiduBS4项目图标,按F5键刷新。得到的结果如图9所示。

图9 Eclipse运行结果

图10 笔记本打开文件

这是因为“百度贴吧_权利的游戏.txt”文件中数据保存的是utf8编码。Eclipse自带的文字编辑器默认支持的是GBK编码,所以会显示乱码。而Windows记事本notepad虽然也默认支持的是GBK,但是它同时也支持utf8编码。

3、代码分析

在项目baiduBS4中除了主程序外,还自定义了一个mylog.py模块。这个模块的作用很明显,就是为了主程序提供log功能。

第27~36行则定义了两个loghandler。一个是将log输出到文本中,一个是将log输出到终端方便调试。第39~52行则按照logging模块定义了5个log级别。

主程序getCommentInfo.py也比较简单。第10~14行还是导入所需的模块。在第17~24行定义了一个新类。主程序里的Item类是仿照Scrapy框架中的items.py写的。Scrapy的框架非常方便,也很合理。也可以完全参考Scrapy的方法,重新建立一个Python模块,将这个类放到一个单独的文件中。

第68~76行把得到的items列表写入到最终的数据保存文件“百度贴吧_权利的游戏.txt”中去。其中还添加了一个try语句,防止写入文件失败。

第93~95行是__main__函数,实例化GetTiebaInfo类。

4、Eclipse调试

虽然在Windows下也可以使用pdb模块对Python程序进行调试。Pdb的强大当然是无须质疑,但直观上来说就远远不如Eclipse了。下面就牛刀小试,实验一下Eclipse的调试功能。

首先要做的是在程序中添加断点,也就是程序运行中暂停中断的位置。在所需中断行的最前方,行号的前面空白处双击右键,会出现一个绿色气球的图标,表明断点已经设立成功。这里只在41行和60行设置了2个断点,如图11所示。

图11 Eclipse设置断点

再单击Eclipse上方菜单栏最右边的爬虫图标,进入调试模式。单击图标栏的爬虫图标开始调试。程序运行到断点处会自动停止运行,单击图标栏的箭头图标进行单步调试。在程序栏中的箭头指向运行的位置。可以在变量标签中观察变量的值。测试完毕后可以单击图标栏的停止图标退出调试,如图12所示。

图12 Eclipse调试

配合log模块,即使程序出现什么问题也可以很容易地找到出错的位置,方便修改。

微信公众号:计算机与网络安全

ID:Computer-network

【推荐书籍】

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190831A072BE00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券