前言

  最近业余在做一个基于.NET Core的搜索项目,奈何基层代码写好了,没有看起来很华丽的数据供测试。很巧的也是博客搜索,于是乎想到了博客园。C#也能做做页面数据抓取的,不过在博客园看到的大部分都是python实现,所以就临时想了一下看看python到底是什么东东,不看基础语法,不看语言功能,直接上代码,哪里不会搜哪里。代码完成总共用时大概4个小时,其中搭建环境加安装BeautifulSoup大概1个小时。解析HTML用时间最多了,边看demo边解析,大概2个小时,剩下的时间就是调试加保存数据了。

环境搭建

  既然用python,那么自然少不了语言环境。于是乎到官网下载了3.5版本的。安装完之后,随机选择了一个编辑器叫PyCharm,话说python编辑器还真挺多的。由于本人是小白,所以安装事项不在过多赘述。

  

  建好项目,打开编辑器,直接开工。本来之前用C#写的时候,大体思路就是获取网页内容,然后正则匹配。后来发现网上的帖子也很多。不过在搜索过程中发现,不建议用正则来匹配HTML。有正好我的正则不太好,所以我就搜了一下HTML解析工具,果不其然,人家都做好了,直接拿来用吧。没错就是这个东东:BeautifulSoup 。安装也很简单,不过中间出了个小插曲,就是bs4没有。继续搜,然后需要用pip安装一下就好了。(当然我并不知道ps4和pip是什么鬼)

  

思路分析

  博客吗,我当然就对准了博客园,于是乎,进入博客园首页,查看请求。

  

发送请求

  当然我不知道python是怎么进行网络请求的,其中还有什么2.0和3.0的不同,中间曲曲折折了不少,最终还是写出了最简单的一段请求代码。

  

  1. import urllib.parse
  2. import urllib.request
  3.  
  4. # params CategoryId=808 CategoryType=SiteHome ItemListActionName=PostList PageIndex=3 ParentCategoryId=0 TotalPostCount=4000
  5. def getHtml(url,values):
  6. user_agent='Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36'
  7. headers = {'User-Agent':user_agent}
  8. data = urllib.parse.urlencode(values)
  9. response_result = urllib.request.urlopen(url+'?'+data).read()
  10. html = response_result.decode('utf-8')
  11. return html
  12.  
  13. #获取数据
  14. def requestCnblogs(index):
  15. print('请求数据')
  16. url = 'http://www.cnblogs.com/mvc/AggSite/PostList.aspx'
  17. value= {
  18. 'CategoryId':808,
  19. 'CategoryType' : 'SiteHome',
  20. 'ItemListActionName' :'PostList',
  21. 'PageIndex' : index,
  22. 'ParentCategoryId' : 0,
  23. 'TotalPostCount' : 4000
  24. }
  25. result = getHtml(url,value)
  26. return result

  其实博客园这个请求还是挺标准的,哈哈正好适合抓取。因为他返回的就是一段html。(如果返回json那不是更好。。。。)

数据解析

  上文已经提到了,用到的是BeautifulSoup,好处就是不用自己写正则,只要根据他的语法来写就好了,在多次的测试之后终于完成了数据的解析。先上一段HTML。然后在对应下面的代码,也许看起来更轻松一些。

  1. <div class="post_item">
  2. <div class="digg">
  3. <div class="diggit" onclick="DiggPost('hyper-xl',6417741,281238,1)">
  4. <span class="diggnum" id="digg_count_6417741">1</span>
  5. </div>
  6. <div class="clear"></div>
  7. <div id="digg_tip_6417741" class="digg_tip"></div>
  8. </div>
  9. <div class="post_item_body">
  10. <h3><a class="titlelnk" href="http://www.cnblogs.com/hyper-xl/p/6417741.html" target="_blank">Python 字符串格式化</a></h3>
  11.  
  12. <p class="post_item_summary">
  13. <a href="http://www.cnblogs.com/hyper-xl/" target="_blank">
  14. <img width="48" height="48" class="pfs"
  15. src="//pic.cnblogs.com/face/795666/20160421231717.png" alt="" />
  16. </a> 转载请注明出处 Python2.6+ 增加了str.format函数,用来代替原有的'%'操作符
  17.  
  18. 。它使用比'%'更加直观、灵活。下面详细介绍一下它的使用方法。 下面是使用'%'的例子: 格式很像C语言的printf是不是?由于'%'是一个操作符,只能在左右
  19.  
  20. 两边各放一个参数,因此右边多个值需要用元组或 ...
  21. </p>
  22.  
  23. <div class="post_item_foot">
  24. <a href="http://www.cnblogs.com/hyper-xl/" class="lightblue">新月的力量_141</a>
  25. 发布于 2017-02-19 23:07
  26. <span class="article_comment">
  27. <a href="http://www.cnblogs.com/hyper-xl/p/6417741.html#commentform" title="" class="gray">
  28. 评论(0)
  29. </a>
  30. </span>
  31. <span class="article_view">
  32. <a href="http://www.cnblogs.com/hyper-xl/p/6417741.html" class="gray">
  33. 阅读
  34.  
  35. (138)
  36. </a>
  37. </span>
  38. </div>
  39. </div>
  40. <div class="clear"></div>
  41. </div>

  通过上文的HTML代码可以看到几点。首先每一条数据都在 div(class="post_item")下。然后 div("post_item_body")下有用户信息,标题,链接,简介等信息。逐一根据样式解析即可。代码如下:

  1. from bs4 import BeautifulSoup
  2. import request
  3. import re
  4.  
  5. #解析最外层
  6. def blogParser(index):
  7.  
  8. cnblogs = request.requestCnblogs(index)
  9. soup = BeautifulSoup(cnblogs, 'html.parser')
  10. all_div = soup.find_all('div', attrs={'class': 'post_item_body'}, limit=20)
  11.  
  12. blogs = []
  13. #循环div获取详细信息
  14. for item in all_div:
  15. blog = analyzeBlog(item)
  16. blogs.append(blog)
  17.  
  18. return blogs
  19.  
  20. #解析每一条数据
  21. def analyzeBlog(item):
  22. result = {}
  23. a_title = find_all(item,'a','titlelnk')
  24. if a_title is not None:
  25. # 博客标题
  26. result["title"] = a_title[0].string
  27. # 博客链接
  28. result["href"] = a_title[0]['href']
  29. p_summary = find_all(item,'p','post_item_summary')
  30. if p_summary is not None:
  31. # 简介
  32. result["summary"] = p_summary[0].text
  33. footers = find_all(item,'div','post_item_foot')
  34. footer = footers[0]
  35. # 作者
  36. result["author"] = footer.a.string
  37. # 作者url
  38. result["author_url"] = footer.a['href']
  39. str = footer.text
  40. time = re.findall(r"发布于 .+? .+? ", str)
  41. result["create_time"] = time[0].replace('发布于 ','')
  42.  
  43. comment_str = find_all(footer,'span','article_comment')[0].a.string
  44. result["comment_num"] = re.search(r'\d+', comment_str).group()
  45.  
  46. view_str = find_all(footer,'span','article_view')[0].a.string
  47. result["view_num"] = re.search(r'\d+', view_str).group()
  48.  
  49. return result
  50.  
  51. def find_all(item,attr,c):
  52. return item.find_all(attr,attrs={'class':c},limit=1)

  上边一堆代码下来,着实花费了我不少时间,边写边调试,边百度~~不过还好最终还是出来了。等数据都整理好之后,然后我把它保存到了txt文件里面,以供其他语言来处理。本来想写个put直接put到ElasticSearch中,奈何没成功。后边在试吧,毕竟我的重点只是导数据,不在抓取这里。

  1. import match
  2. import os
  3. import datetime
  4. import json
  5.  
  6. def writeToTxt(list_name,file_path):
  7. try:
  8. #这里直接write item 即可,不要自己给序列化在写入,会导致json格式不正确的问题
  9. fp = open(file_path,"w+",encoding='utf-8')
  10. l = len(list_name)
  11. i = 0
  12. fp.write('[')
  13. for item in list_name:
  14. fp.write(item)
  15. if i<l-1:
  16. fp.write(',\n')
  17. i += 1
  18. fp.write(']')
  19. fp.close()
  20. except IOError:
  21. print("fail to open file")
  22.  
  23. #def getStr(item):
  24. # return json.dumps(item).replace('\'','\"')+',\n'
  25.  
  26. def saveBlogs():
  27. for i in range(1,2):
  28. print('request for '+str(i)+'...')
  29. blogs = match.blogParser(i,5)
  30. #保存到文件
  31. path = createFile()
  32. writeToTxt(blogs,path+'/blog_'+ str(i) +'.json')
  33. print('第'+ str(i) +'页已经完成')
  34. return 'success'
  35.  
  36. def createFile():
  37. date = datetime.datetime.now().strftime('%Y-%m-%d')
  38. path = '/'+date
  39. if os.path.exists(path):
  40. return path
  41. else:
  42. os.mkdir(path)
  43. return path
  44.  
  45. result = saveBlogs()
  46. print(result)

  上边呢,我取了一百页的数据,也就是大概2000条做测试。

成果验收

  废了好大劲终于写完那些代码之后呢,就可以享受胜利的果实了,虽然是初学者,代码写的很渣,这参考一下,那参考一下,不过还是有些收获的。运行效果如下:

  

  生成的文件:

  

  文件内容:

  

总结

  一个简单的抓取程序就写完了,python还真是TM的好用。以后有空再研究研究吧。代码行数算上空行和注释总共 100 (50+25+25) 行。凑个整数好看点~~现在认识字我感觉就可以上手写程序了。这里百度一下,那里google一下,问题就解决了,程序也出来了,大功告成。

  是时候该和python暂时告别了,继续我的.NET事业。话说上次做rss采集的时候,好多“.NET要完蛋了”,“为什么我们不招.NET” 是什么鬼。 小伙伴们,下次见。

一个Python小白5个小时爬虫经历的更多相关文章

  1. 一个Python小白5个小时爬虫经历 【续】

    前言 昨天实现了python简单的数据采集之后本来还挺高兴的,结果发现在.NET读取txt文件后反序列化总是报错.具体错误原因好像是从txt读取数据之后会自动加一个隐藏的字符串,没错,肉眼看不见,就导 ...

  2. 一个Python小白如何快速完成爬虫

    很人或多或少都听说过python爬虫,但不知道如何通过python爬虫来爬取自己想要的内容,今天我就给大家说一个爬虫教程来实现自己第一次python爬虫. 环境搭建 既然用python,那么自然少不了 ...

  3. 一个python小白的学习之路

    本人是个网管,在佛山工作,现在已经学习了一段时间python了,还是学开基础,但近段时间有一点的突破出来了,找到了一个很好的自学视频,等自己有能力了就想找一个特训班试试.已经看了视频两个星期了,有小小 ...

  4. python小白的初步爬虫

    前序:  最近工作不是很忙,领导突然找我谈话,说是谈话,其实就是分配活呗.果不其然,很快进入正题, 给了我一个网址链接,然后说需要商品的信息...巴拉巴拉.好吧,去做吧. 我当时的内心是崩溃的,pyt ...

  5. 一个python爬虫小程序

    起因 深夜忽然想下载一点电子书来扩充一下kindle,就想起来python学得太浅,什么“装饰器”啊.“多线程”啊都没有学到. 想到廖雪峰大神的python教程很经典.很著名.就想找找有木有pdf版的 ...

  6. 第三百五十节,Python分布式爬虫打造搜索引擎Scrapy精讲—selenium模块是一个python操作浏览器软件的一个模块,可以实现js动态网页请求

    第三百五十节,Python分布式爬虫打造搜索引擎Scrapy精讲—selenium模块是一个python操作浏览器软件的一个模块,可以实现js动态网页请求 selenium模块 selenium模块为 ...

  7. 我的第一个python web开发框架(21)——小结

    这个小网站终于成功上线,小白除了收获一笔不多的费用外,还得到女神小美的赞赏,心中满满的成就感.这一天下班后,他请老菜一起下馆子,兑现请吃饭的承诺,顺便让老菜点评一下. 小白:老大,在你的指导下终于完成 ...

  8. python小白入门

    阅读目录 一python介绍 二安装python解释器 三第一个python程序 四变量 五用户与程序交互 六基本数据类型 七格式化输出 八基本运算符 九流程控制之if...else 十流程控制之wh ...

  9. Python小白的数学建模课-A3.12 个新冠疫情数模竞赛赛题与点评

    新冠疫情深刻和全面地影响着社会和生活,已经成为数学建模竞赛的背景帝. 本文收集了与新冠疫情相关的的数学建模竞赛赛题,供大家参考,欢迎收藏关注. 『Python小白的数学建模课 @ Youcans』带你 ...

随机推荐

  1. 关于Apache,Mysql,PHP之间的关系

    声明:以下为作者原创,转载请注明文章来源地址. 通过百度百科我们知道 Apache(全称Apache HTTP Server):是世界使用排名第一的Web服务器软件.可以在大多数计算机操作系统中运行, ...

  2. 【Xilinx-Petalinux学习】-07-OpenCV的软硬件处理速度对比

    有空了设计一个hls的图像处理IP. 通过hls设计ip模块实现opencv的图像处理. 对比软件和硬件的图像处理速度.

  3. CentOS标准目录结构

    原博:http://www.centoscn.com/CentOS/2014/0424/2861.html/ 最高层root --- 启动Linux时使用的一些核心文件.如操作系统内核.引导程序Gru ...

  4. UITableView 之 取消选中

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [table ...

  5. IOC容器Unity的使用及独立配置文件Unity.Config

    [本段摘录自:IOC容器Unity 使用http://blog.csdn.net/gdjlc/article/details/8695266] 面向接口实现有很多好处,可以提供不同灵活的子类实现,增加 ...

  6. Centos下关于ssh、scp与rsync设置与应用

    最近应公司要求,需要对文件数据进行远程传输与备份操作,特此写了一篇文章记录下了关于ssh.scp以及rsync的应用配置全过程,可能过程太过罗嗦,但主要就是想在不遗漏每个过程的情况下对此进行阐述,希望 ...

  7. volatile的理解和使用

    package thread; /** * Created by Administrator on 2017/1/15. */ public class Counter { public volati ...

  8. Win7 x64 Eclipse无法识别手机 / adb interface有黄色感叹号,无法识别

    今天公司停电,因此把安卓项目带回宿舍做.宿舍的笔记本,装的是Win7 x64,手机连上电脑后,windows可以识别,但Eclipse的DDMS中却无法识别,什么都没有: 然后打开设备管理器查看,发现 ...

  9. Delphi遍历文件夹及子文件夹(可查找固定格式文件)

    Delphi遍历文件夹及子文件夹 {-------------------------------------------------------------------------------过程名 ...

  10. AngularJS中$http服务的简单用法

    我们可以使用内置的$http服务直接同外部进行通信.$http服务只是简单的封装了浏览器原生的XMLHttpRequest对象. 1.链式调用 $http服务是只能接受一个参数的函数,这个参数是一个对 ...