Python爬虫实战(1):抓取毒舌电影最新推送


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自行增加语句的位置。

待改进之处

  1. 网页迭代的高效性:目前网页迭代是依靠给定的数值,页面中有相关数值可使用,如何将其提取提取出来并融合进循环中,是一个有待研究的问题。
  2. 网页读取的稳定性:这是直接影响到一个爬虫是否实用的地方。正如上文所述,希望能利用ip代理以解决http状态为403的问题,同时也寻求其他方法。
  3. 提取更多信息:每个条目中还包括一条句子,可以使用正则表达式提取并添加在列表中
  4. 尝试其他存储方法:学习并练习MySQL,MongoDB等数据库进行存储。

总结

​ 本文详细介绍了一个可用的毒舌电影文章列表爬虫的程序代码,并详解了每个函数的功能,部分语句给出了注释。可供新手童鞋学习参考。

参考链接

segalou/doubanmovie_spyder

猜你喜欢

转载自blog.csdn.net/u013023297/article/details/71402775