update:6/11/2017 由于毒舌电影公众号被关闭账号,源码已失效,可参考并调整相关参数以适配网站上其他公众号文章的抓取,望周知。
~~~~~~~~~~~
作为一个电影爱好者,“毒舌电影”是我比较关注的公众号号,昨天偶然发现传送门这么一个网站,可以在线阅读微信公众号,结合基础知识,一个豆瓣爬虫范本以及网上的资料进行阅读学习,形成一个可以使用的毒舌电影最新推送爬虫。
GitHub链接:毒舌电影最新推送爬虫1.0,使用Python2.7进行编写。
接下来我会分别讲解各个函数模块如何实现功能,一些待改进的地方,最后进行总结。
模块讲解
1.导入包,初始化链接以及Header
代码如下
from bs4 import BeautifulSoup #美丽汤模块,解析网页
import numpy as np #取随机数
import csv #写csv文件
from urllib2 import Request, urlopen, URLError, HTTPError #打开网页,报错信息
download_url = 'http://chuansong.me/account/dsmovie/recent'
headers=[
{'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'},\
{'User-Agent':'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11'},\
{'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'},\
{'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0'}] #四个备选header,缺少header则返回403错误
2.拼接URL
def updateurl(num):
item_num = num * 12
url = 'http://chuansong.me/account/dsmovie?start=' + str(item_num)
return url
num 给页面计数,是页面链接的值-1,初始值为0,读取完一个界面后,num自动+1,因为每个页面显示12条推送,故实际页面的url链接尾部数字为12的倍数,item_num为整型变量,需使用str函数转换成字符。
3.读取链接并返回源代码
def get_raw_html(url):
req = Request(url,headers=headers[np.random.randint(0,4)]) #随机取header
try:
response = urlopen(req,timeout = None).read() 设置timeout以防止频繁出现403错误
except HTTPError, e:
print 'Error code: ', e.code
except URLError, e:
print 'Reason: ', e.reason
else:
print 'Success'
return response
这段很简单,设定urlopen参数与Request参数,给一个url链接,返回网页源代码。
后续也将在此处继续进行优化,主要问题是爬取页面一旦超过5个,即会在爬取中出现Error code:403错误,并显示local variable ‘response’ referenced before assignment,即页面无法打开,导致后续bs4解析返回空值,从而导致爬取失败。
初步思路是考虑更换ip代理,也在寻找其他解决方法。
4.解析网页并返回文章列表
def parse_html(html):
bsObj = BeautifulSoup(html)
article_list = bsObj.find('div',{'class':'main_col col w4_5'})
articles_list_result = []
for article in article_list.find_all('div',{'class':'pagedlist_item'}):
link = 'http://chuansongmen.me'
title = article.find('a').getText()
link_part = article.find('a')['href']
link = link + link_part
time = article.find('span',{'class':'timestamp'}).getText()
articles_list_result.append( [title,link,time] )
next_page = bsObj.find('div',{'style':'text-align: center;'}).find('a')
if next_page:
return articles_list_result, next_page['href']
return articles_list_result
典型的BeautifulSoup解析思路,首先在页面中点击审查元素,寻找到包含有推送文章列表的HTML代码段(后统称代码块),其次寻找一个代码块,使其包含这个段,并且具有唯一特征(标签名,属性名,属性值),使用find定位到这个块,赋值给article_list,再从list中寻找每条推送所在的最小代码段,取其唯一特征(同上),使用find_all定位。
接下来即是提取每个段的信息,该站上每条推送包含标题,站内链接,时间以及一条不明属性句子,介于本身能力以及兴趣,只提取前三类信息。其中标题,时间可以先定位所在标签,后使用getText函数进行提取,而站内链接则需要先定位提取,后与网站首页链接进行拼接后得到。提取后以列表形式赋值到articles_list_result。
当解析到下一页所在代码块时,仅使用其非False属性,返回已有的list_result以及next_page所在标签内含的站内链接,此处后续可进行改进。
潜在问题:一旦3中的网页读取出错,输入本函数的html则为空,即会使find_all函数出错,出现
'NoneType' object has no attribute 'find_all'
或
'NoneType' object has no attribute 'getText'
两种错误,所以网页读取直接影响最终爬虫效果。
5.写出到CSV文件
def export_to_csv(article_list_result):
csvFile = open("article-recent2.csv","wb")
csvFile.write('\xEF\xBB\xBF')
writer = csv.writer(csvFile)
writer.writerow(["Title","link","Time"])
try:
for page_result in article_list_result:
for article in page_result:
article[0] = article[0].encode('utf-8')
writer.writerow(article)
finally:
csvFile.close()
这段基本是全面取自参考链接中代码的,大致流程即是以二进制文件形式打开一个名为article-recent2.csv的文件,若不存在即新建一个空文件,依次每行写入list_result中的数据,最后关闭文件。
其中article[0]若不声明以’UTF-8’编码,则会出现下述错误,具体原因有待研究。
'ascii' codec can't encode characters in position 1-11: ordinal not in range(128)
6.主函数
def main():
result = []
num = 0
while num < 10:
url = updateurl(num)
html = get_raw_html(url)
articles,url_part = parse_html(html)
result.append(articles)
num += 1
export_to_csv(result)
print 'export done'
if __name__=='__main__':
main()
各个函数写好后组合在一起即可,注意循环运行的逻辑条件以及num自行增加语句的位置。
待改进之处
- 网页迭代的高效性:目前网页迭代是依靠给定的数值,页面中有相关数值可使用,如何将其提取提取出来并融合进循环中,是一个有待研究的问题。
- 网页读取的稳定性:这是直接影响到一个爬虫是否实用的地方。正如上文所述,希望能利用ip代理以解决http状态为403的问题,同时也寻求其他方法。
- 提取更多信息:每个条目中还包括一条句子,可以使用正则表达式提取并添加在列表中
- 尝试其他存储方法:学习并练习MySQL,MongoDB等数据库进行存储。
总结
本文详细介绍了一个可用的毒舌电影文章列表爬虫的程序代码,并详解了每个函数的功能,部分语句给出了注释。可供新手童鞋学习参考。
参考链接