您现在的位置是:首页 > 学无止境 > Python 网站首页学无止境

利用scrapy爬取知乎信息(二)

简介在前一篇文章中,我们已经构造好了一个可以发散爬取的Spider,接下来,我们就解决一下数据储存和请求头、代理等中间件的问题。

4、将数据存入mongoDB


我们在前面已经安装了pymongo,我们可以借助其来进行对mongoDB的操作。打开pipelines.py,在这里面我们可以对Item进行一些操作,例如对其进行一些清洗、验证、数据库储存等等。

class MongoPipeline(object):
    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_db=crawler.settings.get('MONGO_DB'),
            mongo_uri=crawler.settings.get('MONGO_URI')
        )

    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]

    def process_item(self, item, spider):
        if isinstance(item, UserItem):
            self.db['user'].insert(dict(item))
        elif isinstance(item, RelationItem):
            self.db['relation'].insert(dict(item))
        elif isinstance(item, AnswerItem):
            self.db['answer'].insert(dict(item))
        elif isinstance(item, QuestionItem):
            self.db['question'].insert(dict(item))
        elif isinstance(item, ArticleItem):
            self.db['article'].insert(dict(item))
        return item

    def close_spider(self, spider):
        self.client.close()

其中:

from_crawler:这是一个类方法,它的参数就是crawler,通过crawler我们就可以拿到全局配置的每个配置信息。在这里,这个方法的定义主要是用来获取settings.py中的配置。

open_spider:当Spider开启时,这个方法就会被调用。在这里,我们进行mongoDB的连接和数据库的选择。

close_spider:当Spider关闭时,这个方法被调用。在这里,我们进行mongoDB连接的关闭。

process_item:这个方法则执行数据的插入操作。在这里我们根据Item的类型来插入到不同的collection之中。

然后在settings.py中加入以下代码,就完成了存入数据库的操作了

ITEM_PIPELINES = {
   'zhihuSpider.pipelines.MongoPipeline': 300,
}

MONGO_URI = '127.0.0.1'
MONGO_DB = 'zhihu'


5、请求头、代理


到了这里,我们的爬虫已经完成了数据爬取、数据储存等工作了,但是为了可以更长时间的爬取,我们需要伪装成浏览器,同时也要解决IP被封的问题。所以我们就需要为我们的请求加上请求头和代理了。打开middlewares.py,在这里我们可以对请求和响应进行一些处理。如对请求加上请求头、代理等。

from .settings import *
import random

class HeadersMiddleware(object):
    def __init__(self):
        self.user_agents = [
            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
            'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
            'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0'
        ]

    def process_request(self, request, spider):
        request.headers['User-Agent'] = random.choice(self.user_agents)
        request.headers['Cookie'] = random.choice(COOKIE)

在settings.py中,我们存入了一些账户的cookie,用来做登录认证。在process_request()方法中,我们对每一个请求都加上一个UA和一个用户登录之后的COOKIE,这样就可以伪装成用户使用浏览器获取数据了。

解决了请求头的问题,现在我们就来解决一下代理的问题。使用的代理来源可以是来自于一些服务商、也可以是来自自己维护的代理池。在这里推荐一下博主崔庆才提供的代理池: ProxyPool。然后我们就可以开始编写使用代理的中间件代码了

import logging
from w3lib.url import safe_url_string
from six.moves.urllib.parse import urljoin
from scrapy.exceptions import IgnoreRequest

# 访问重试时使用代理
class ProxyMiddleware(object):
    def __init__(self, proxy_url):
       # self.logger = logging.getLogger(__name__)
        self.proxy_url = proxy_url

    # 获取一个随机代理
    def get_random_proxy(self):
        try:
            response = requests.get(self.proxy_url)
            if response.status_code == 200:
                proxy = response.text
                return proxy
        except requests.ConnectionError:
            return False

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            proxy_url=crawler.settings.get('PROXY_URL')
        )

    def process_request(self, request, spider):
        # logging.info(request.headers)
        if request.meta.get('retry_times'):
            proxy = self.get_random_proxy()
            if proxy:
                uri = 'https://{proxy}'.format(proxy=proxy)
                request.meta['proxy'] = uri
                logging.debug("使用代理 " + uri)


# 页面返回码为403、302时使用代理
class Proxy403Middleware(object):

    def __init__(self, settings):
        self.proxy_status = [302, 403]
        self.proxy_url = settings.get('PROXY_URL')

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            settings=crawler.settings
        )


    # 我们在process_response()方法中对响应处理,如果响应码为403或者302时,说明此时我们的IP被被封了,或者我们当前使用的用户COOKIE访问太频繁,需要输入验证码了。所以此时我们加上代理对产生该响应的请求再次请求。
    def process_response(self, request, response, spider):
        if (request.meta.get('dont_redirect', False) or
                response.status in getattr(spider, 'handle_httpstatus_list', []) or
                response.status in request.meta.get('handle_httpstatus_list', []) or
                request.meta.get('handle_httpstatus_all', False)):
            return response

        if response.status in self.proxy_status:
            if 'Location' in response.headers:
                location = safe_url_string(response.headers['location'])
                redirected_url = urljoin(request.url, location)
            else:
                redirected_url = ''

            # AutoProxy for first time
            if not request.meta.get('auto_proxy'):
                proxy = self.get_random_proxy()
                uri = 'https://{proxy}'.format(proxy=proxy)
                request.meta.update({'auto_proxy': True, 'proxy': proxy})
                new_request = request.replace(meta=request.meta, dont_filter=True)
                new_request.priority = request.priority + 2
                spider.log('Will AutoProxy for <{} {}> {}'.format(
                    response.status, request.url, redirected_url))
                return new_request

            # IgnoreRequest for second time
            else:
                spider.logger.warn('Ignoring response <{} {}>: HTTP status code still in {} after AutoProxy'.format(
                    response.status, request.url, self.proxy_status))
                raise IgnoreRequest
        return response

    # 获取一个随机代理
    def get_random_proxy(self):
        try:
            response = requests.get(self.proxy_url)
            if response.status_code == 200:
                proxy = response.text
                return proxy
        except requests.ConnectionError:
            return False

完成之后,类似pipelines.py,我们还需要在settings.py中启用这些中间件,同时我们还需要把代理池的url写入settings.py之中。

DOWNLOADER_MIDDLEWARES = {
    'zhihuSpider.middlewares.HeadersMiddleware': 554,
    'zhihuSpider.middlewares.ProxyMiddleware': 555,
    'zhihuSpider.middlewares.Proxy403Middleware': 601,
}

PROXY_URL = 'http://127.0.0.1:5555'

至此,我们已经为爬虫加上了请求头和代理。


版权声明:本文为博主原创文章,转载时请注明来源。https://blog.thinker.ink/passage/18/

 

文章评论

Top