基于scrapy框架的Python爬虫爬取新浪新闻

新浪部分网页可能已经改版,故本文有些代码可能已经不适用了,仅提供一个思路。

一、简单思路

下图新浪新闻中心的首页,也就是我们要爬取的第一页新浪新闻中心的国际板块

《基于scrapy框架的Python爬虫爬取新浪新闻》 1

此页下拉发现有五个小栏目:

《基于scrapy框架的Python爬虫爬取新浪新闻》 2

每个小栏目下拉会继续加载页面,同时加载到最底下还会发现有翻页选项:

《基于scrapy框架的Python爬虫爬取新浪新闻》 3

在Chrome中打开调试者工具(F12),进入Network选项,点击JS:

《基于scrapy框架的Python爬虫爬取新浪新闻》 4

刷新页面,下拉加载新闻,观察调试者工具中的变化:

《基于scrapy框架的Python爬虫爬取新浪新闻》 5

可以发现,每下拉加载一次或点击翻页就会请求一个新的网页,这个网页和前一页的区别就是在page的值上发生了变化,如图5Request URL处所示。理论上来说,根据这一规律可以将这一栏目的所有新闻全部爬取。

下面再看五个小栏目的区别:分别点开,观察调试者工具中的变化:

对于亚洲栏目:

http://api.roll.news.sina.com.cn/zt_list?channel=news&cat_1=gjxw&cat_3=gj-yz&level==1||=2&show_ext=1&show_all=1&show_num=22&tag=1&format=json&page=1&callback=newsloadercallback&_=1517556788882

对于欧洲栏目:

http://api.roll.news.sina.com.cn/zt_list?channel=news&cat_1=gjxw&cat_3=gj-oz&level==1||=2&show_ext=1&show_all=1&show_num=22&tag=1&format=json&page=3&callback=newsloadercallback&_=1517557031988

发现除page以外唯一的区别就是cat-3的值不同,结合前面提到的page变化,可以爬取五个栏目的不同页的新闻。同时也可以进入国内、社会、军事等其他具有类似结构的页面进行爬取。

思路:首先在parse中,设置两层循环,提取不同栏目下不同页面所有新闻的URL,同时返回这些URL的Request,并且通过item传递URL到parse_item回调函数。再用parse_item解析这些新闻页面,提取出标题和内容,将item传入Pipeline对爬取的数据进行存储。

二、部分代码

1、items

《基于scrapy框架的Python爬虫爬取新浪新闻》 6

2、pipelines

《基于scrapy框架的Python爬虫爬取新浪新闻》 7

3、settings

《基于scrapy框架的Python爬虫爬取新浪新闻》 8
《基于scrapy框架的Python爬虫爬取新浪新闻》 9
《基于scrapy框架的Python爬虫爬取新浪新闻》 10
《基于scrapy框架的Python爬虫爬取新浪新闻》 11

3、middlewares

可以保留默认的middlewares内容,如下为添加的,用于随机选择代理IP和代理浏览器(代理IP不一定可用,可以上网寻找可用的免费代理IP):

from scrapy import signals

import random

import base64

from SinaBot.settings import PROXIES

class RandomUserAgent(object):

“””Randomly rotate user agents based on a list of predefined ones”””

    def __init__(self, agents):

        self.agents = agents

    @classmethod

    def from_crawler(cls, crawler):

         return cls(crawler.settings.getlist(‘USER_AGENTS’))

    def process_request(self, request, spider):

        print(“**************************” + random.choice(self.agents))

        request.headers.setdefault(‘User-Agent’, random.choice(self.agents))

class ProxyMiddleware(object):

    def process_request(self, request, spider):

        proxy = random.choice(PROXIES)

        if proxy[‘user_pass’]is not None:

            request.meta[‘proxy’] =”http://%s” % proxy[‘ip_port’]

            encoded_user_pass = base64.encodestring(proxy[‘user_pass’].encode(“utf-8”)).decode(“utf-8”)

            request.headers[‘Proxy-Authorization’] =’Basic ‘ + encoded_user_pass

            print(“**************ProxyMiddleware have pass************” + proxy[‘ip_port’])

       else:

            print(“**************ProxyMiddleware no pass************” + proxy[‘ip_port’])

            request.meta[‘proxy’] =”http://%s” % proxy[‘ip_port’]

       pass

4、SinaSpider

《基于scrapy框架的Python爬虫爬取新浪新闻》 12
《基于scrapy框架的Python爬虫爬取新浪新闻》 13
《基于scrapy框架的Python爬虫爬取新浪新闻》 14

三、爬取结果

上万条新闻,如果想爬取特定的页数,同样也可以对Spider中的min_page_num和max_page_num做限制。

《基于scrapy框架的Python爬虫爬取新浪新闻》 15

问题:新老新闻的URL格式会发生变化,采用同样的正则表达式会出现老新闻不能提取的问题。

下一步关注点:如何做全站爬取,如何获取可靠的代理IP。

(1)关于全站爬取:推荐使用提取链接(LinkExtractor)的方法,不断提出对于新闻页的请求,将不是新闻页的链接筛掉。不断循环往复,构造多个爬虫,从同一网站的多个站点开始爬取,最终爬取全站内容。几乎可以爬取各类主要新闻网页的全站。

(2)关于代理IP:Crawlera或者Goagent, 也可以花钱购买服务,不过一般会有抓取次数限制,而且高质量的服务价格更昂贵。

    原文作者:Nise9s
    原文地址: https://www.jianshu.com/p/79a74f48979d
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞