最近业余在做一个基于. 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 的不同,中间曲曲折折了不少,最终还是写出了最简单的一段请求代码。
- import urllib.parse
- import urllib.request
- # params CategoryId=808 CategoryType=SiteHome ItemListActionName=PostList PageIndex=3 ParentCategoryId=0 TotalPostCount=4000
- def getHtml(url,values):
- user_agent='Mozilla/5.0 (Windows NT 6.3; WOW64) ApplewebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36'
- headers = {'User-Agent':user_agent}
- data = urllib.parse.urlencode(values)
- response_result = urllib.request.urlopen(url+'?'+data).read()
- html = response_result.decode('utf-8')
- return html
- #获取数据
- def requestCnblogs(index):
- print('请求数据')
- url = 'http://www.cnblogs.com/mvc/AggSite/PostList.aspx'
- value= {
- 'CategoryId':808,
- 'CategoryType' : 'SiteHome',
- 'ItemListActionName' :'PostList',
- 'PageIndex' : index,
- 'ParentCategoryId' : 0,
- 'TotalPostCount' : 4000
- }
- result = getHtml(url,value)
- return result
其实博客园这个请求还是挺标准的,哈哈正好适合抓取。因为他返回的就是一段 html。(如果返回 json 那不是更好。。。。)
上文已经提到了,用到的是 BeautifulSoup,好处就是不用自己写正则,只要根据他的语法来写就好了,在多次的测试之后终于完成了数据的解析。先上一段 HTML。然后在对应下面的代码,也许看起来更轻松一些。
通过上文的 HTML 代码可以看到几点。首先每一条数据都在 div(class="post_item") 下。然后 div("post_item_body") 下有用户信息,标题,链接,简介等信息。逐一根据样式解析即可。代码如下:
- from bs4 import BeautifulSoup
- import request
- import re
- #解析最外层
- def blogParser(index):
- cnblogs = request.requestCnblogs(index)
- soup = BeautifulSoup(cnblogs, 'html.parser')
- all_div = soup.find_all('div', attrs={'class': 'post_item_body'}, limit=20)
- blogs = []
- #循环div获取详细信息
- for item in all_div:
- blog = analyzeBlog(item)
- blogs.append(blog)
- return blogs
- #解析每一条数据
- def analyzeBlog(item):
- result = {}
- a_title = find_all(item,'a','titlelnk')
- if a_title is not None:
- # 博客标题
- result["title"] = a_title[0].string
- # 博客链接
- result["href"] = a_title[0]['href']
- p_summary = find_all(item,'p','post_item_summary')
- if p_summary is not None:
- # 简介
- result["summary"] = p_summary[0].text
- footers = find_all(item,'div','post_item_foot')
- footer = footers[0]
- # 作者
- result["author"] = footer.a.string
- # 作者url
- result["author_url"] = footer.a['href']
- str = footer.text
- time = re.findall(r"发布于 .+? .+? ", str)
- result["create_time"] = time[0].replace('发布于 ','')
- comment_str = find_all(footer,'span','article_comment')[0].a.string
- result["comment_num"] = re.search(r'\d+', comment_str).group()
- view_str = find_all(footer,'span','article_view')[0].a.string
- result["view_num"] = re.search(r'\d+', view_str).group()
- return result
- def find_all(item,attr,c):
- return item.find_all(attr,attrs={'class':c},limit=1)
上边一堆代码下来,着实花费了我不少时间,边写边调试,边百度~~ 不过还好最终还是出来了。等数据都整理好之后,然后我把它保存到了 txt 文件里面,以供其他语言来处理。本来想写个 put 直接 put 到 ElasticSearch 中,奈何没成功。后边在试吧,毕竟我的重点只是导数据,不在抓取这里。
- import match
- def writeToTxt(list_name,file_path):
- try:
- fp = open(file_path,"w+",encoding='utf-8')
- for item in list_name:
- fp.write(getStr(item))
- fp.close()
- except IOError:
- print("fail to open file")
- def getStr(item):
- return str(item)+'\n'
- def saveBlogs():
- for i in range(1,100):
- blogs = match.blogParser(i)
- #保存到文件
- writeToTxt(blogs,'blog_'+ str(i) +'.txt')
- print('第'+ str(i) +'页已经完成')
- return 'success'
- result = saveBlogs()
- print(result)
上边呢,我取了一百页的数据,也就是大概 2000 条做测试。
废了好大劲终于写完那些代码之后呢,就可以享受胜利的果实了,虽然是初学者,代码写的很渣,这参考一下,那参考一下,不过还是有些收获的。运行效果如下:
生成的文件:
文件内容:
一个简单的抓取程序就写完了,python 还真是 TM 的好用。以后有空再研究研究吧。代码行数算上空行和注释总共 100 (50+25+25) 行。凑个整数好看点~~ 现在认识字我感觉就可以上手写程序了。这里百度一下,那里 google 一下,问题就解决了,程序也出来了,大功告成。
是时候该和 python 暂时告别了,继续我的. NET 事业。话说上次做 rss 采集的时候,好多 ".NET 要完蛋了","为什么我们不招. NET" 是什么鬼。 小伙伴们,下次见。
来源: http://www.cnblogs.com/saper/p/6421687.html