您现在的位置是:首页 > 学无止境 > Python 网站首页学无止境
利用scrapy爬取知乎信息(二)
- Python
- 2018年11月11日 15:11
- 1320已阅读
- 15
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/