Python爬虫项目实战-基于Flask、MongoDB异步构建免费高可匿IP池

   日期:2020-05-12     浏览:156    评论:0    
核心提示:目录一、基础项目结构及解释二、具体代码实现2.1 采集模块2.2 校验模块2.3 数据模块2.4 检测模块2.5 API模块2.6 工具模块2.7 数据模型、配置文件、主程序三、项目结果展示3.1 数据库展示3.2 Web页面展示(三种,挑选了一个展示)一、基础项目结构及解释代理池目的:当同一个IP对某网站访问次数过多,就会限制IP访问,所以我们需要从网上不稳定的代理IP中抽取高可用IP,供爬虫使用。爬取代理池工作流程:多个代理IP网站-py.爬虫

目录

 

一、基础项目结构及解释

二、具体代码实现

2.1 采集模块

2.2 校验模块

2.3 数据模块

2.4 检测模块

2.5 API模块

2.6 工具模块

2.7 数据模型、配置文件、主程序

三、项目结果展示

3.1 数据库展示

3.2 Web页面展示(三种,挑选了一个展示)

一、基础项目结构及解释

代理池目的:当同一个IP对某网站访问次数过多,就会限制IP访问,所以我们需要从网上不稳定的代理IP中抽取高可用IP,供爬虫使用。
爬取代理池工作流程:多个代理IP网站-pyspider抓取-proxy_validate校验(响应速度,协议类型,匿名类型)-将可用代理IP存入数据库
使用代理IP流程:proxy_test检测数据库中的代理IP-更新或者删除代理IP(分数减一,为0则删除)-proxy_api提供稳定代理IP服务接口(获取质量/得分高的IP)
模块抽取:采集模块,校验模块,数据模块,检测模块,API模块,工具模块(日志记录,http模块)

二、具体代码实现

2.1 采集模块

# base_spider.py
#!/usr/bin/env python

# -*- encoding: utf-8 -*-

'''
@Author  :   {Jack Zhao}

@Time    :   2020/5/9 8:45

@Contact :   {zc_dlmu@163.com}

@Desc    :  通用爬虫,作为父类,指定URL列表,分组Xpath(包含ip列表的标签)和组内Xpath(ip: ...port:..)
'''
import requests

from domain import Proxy
from utils.http import get_request_headers
from lxml import etree


class BaseSpider(object):
	# 指定URL列表,分组Xpath(包含ip列表的标签)和组内Xpath(ip: ...port:..)
	urls = []
	group_xpath = ''
	detail_xpath = {}

	def __init__(self,urls=[],group_xpath='',detail_xpath={}):
		if urls:
			self.urls = urls
		if group_xpath:
			self.group_xpath = group_xpath
		if detail_xpath:
			self.detail_xpath = detail_xpath

	def get_page_from_url(self,url):
		'''根据url请求,获取页面数据'''
		response = requests.get(url,headers=get_request_headers())
		return response.content

	def get_first_from_list(self,lis):
		# 检查是否为空
		return lis[0] if len(lis)!=0 else ''

	def get_proxies_from_page(self,page):
		'''解析界面,提取数据,封装为Proxy对象'''
		element = etree.HTML(page)
		# 获取包含ip的标签列表
		trs = element.xpath(self.group_xpath)
		# 遍历,获取相关信息
		for tr in trs:
			ip = self.get_first_from_list(tr.xpath(self.detail_xpath['ip']))
			port = self.get_first_from_list(tr.xpath(self.detail_xpath['port']))
			area = self.get_first_from_list(tr.xpath(self.detail_xpath['area']))
			proxy = Proxy(ip,port,area=area)
			# 使用生成器返回提取到的数据
			yield proxy

	def get_proxies(self):
		# 遍历url
		for url in self.urls:
			# 发送请求,获取页面数据
			page = self.get_page_from_url(url)
			# 解析界面,提取数据,封装为Proxy对象
			# 这里是个生成器
			proxies = self.get_proxies_from_page(page)
			# 返回Proxy对象列表
			yield from proxies

if __name__ == '__main__':

	config = {
		'urls': ['http://www.ip3366.net/free/?stype=1&page={}'.format(i) for i in range(4)],
		# 使用Xpath-Helper工具,同时在Network面板中检查对应js查看是否真的具有tbody
		'group_xpath':'/*;q=0.8,application/signed-exchange;v=b3',
		'Accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
		'Referer': 'https://www.baidu.com',
		'Accept-Encoding': 'gzip, deflate,br',
		'Connection': 'keep-alive',
	}
	return headers


if __name__ == '__main__':
	# 测试随机效果
	print(get_request_headers())
	print("------------" * 20)
	print(get_request_headers())
# log.py
#!/usr/bin/env python

# -*- encoding: utf-8 -*-

'''
@Author  :   {Jack Zhao}

@Time    :   2020/5/9 8:47

@Contact :   {zc_dlmu@163.com}

@Desc    :  记录日志信息
'''


import sys, os
# Python的标准日志模块:logging
import logging
from settings import LOG_LEVEL, LOG_FMT, LOG_DATEFMT, LOG_FILENAME

# 将上级目录添加到搜索路径中
sys.path.append("../")




class Logger(object):

	def __init__(self):
		# 获取一个logger对象
		self._logger = logging.getLogger()
		# 设置format对象
		self.formatter = logging.Formatter(fmt=LOG_FMT, datefmt=LOG_DATEFMT)
		# 日志输出——文件日志模式
		self._logger.addHandler(self._get_file_handler(LOG_FILENAME))
		# 日志输出——终端日志模式
		self._logger.addHandler(self._get_console_handler())
		# 4. 设置日志等级
		self._logger.setLevel(LOG_LEVEL)

	def _get_file_handler(self, filename):
		'''
		:return: 文件日志handler
		'''
		# 获取一个输出为文件日志的handler
		filehandler = logging.FileHandler(filename=filename, encoding="utf-8")
		# 设置日志格式
		filehandler.setFormatter(self.formatter)
		# 返回
		return filehandler

	def _get_console_handler(self):
		'''
		:return 输出到终端日志handler
		'''
		# 获取一个输出到终端的日志handler,标准输出流
		console_handler = logging.StreamHandler(sys.stdout)
		# 设置日志格式
		console_handler.setFormatter(self.formatter)
		# 返回handler
		return console_handler

	# 属性装饰器,返回一个logger对象,可以直接使用该对象调用方法
	@property
	def logger(self):
		return self._logger


# 初始化并配一个logger对象,达到单例
# 使用时,直接导入logger就可以使用
logger = Logger().logger

if __name__ == '__main__':
	print(logger)
	logger.debug("调试信息")
	logger.info("状态信息")
	logger.warning("警告信息")
	logger.error("错误信息")
	logger.critical("严重错误信息")

2.7 数据模型、配置文件、主程序

# domain.py
#!/usr/bin/env python

# -*- encoding: utf-8 -*-

'''
@Author  :   {Jack Zhao}

@Time    :   2020/5/9 8:46

@Contact :   {zc_dlmu@163.com}

@Desc    :  定义代理IP的数据模型类
'''

from settings import MAX_SCORE


class Proxy(object):
	def __init__(self,ip,port,protocol=-1,nick_type=-1,speed=-1,area=None,score=MAX_SCORE,disable_domains=[]):
		# ip: ip地址
		self.ip = ip
		# port: 端口号
		self.port = port
		# protocol: http为0,https为1,http和https都支持是2
		self.protocol = protocol
		# nick_type: 高匿为0,匿名为1,透明为2
		self.nick_type = nick_type
		# speed: 响应速度,s
		self.speed = speed
		# area: 代理ip所在地区
		self.area =area
		# score: 代理ip评分,衡量可用性
		self.score = score
		# 默认分值在settings进行配置,请求失败-1,减为0删除
		# disable_domains:不可用域名列表,有些ip在有些域名下可用,但在其他ip下不可用
		self.disable_domains = disable_domains

	def __str__(self):
		# 返回数据字符串
		return str(self.__dict__)
# settings.py
#!/usr/bin/env python

# -*- encoding: utf-8 -*-

'''
@Author  :   {Jack Zhao}

@Time    :   2020/5/9 8:48

@Contact :   {zc_dlmu@163.com}

@Desc    :  常见的变量修改
'''

MAX_SCORE = 50 # 代理ip的默认分数
# 日志配置信息
import logging
LOG_LEVEL = logging.DEBUG # 日志等级
LOG_FMT = '%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s: %(message)s' # 输出日志的格式
LOG_DATEFMT = '%Y-%m-%d %H:%M:%S' # 日志时间的格式
LOG_FILENAME = 'log.log' # 日志输出文件的名称
#测试代理IP超时时间
TEST_TIMEOUT = 10
#MongoDB数据库的URL
MONGO_URL = 'mongodb://127.0.0.1:27017'

# 配置爬虫,根据字符串创建类的对象
'''爬虫的全类名,路径:模块.类名'''
PROXIES_SPIDERS = [
	'core.proxy_spider.proxy_spiders.Free89ipSpider',
	'core.proxy_spider.proxy_spiders.Ip3666Spider',
	'core.proxy_spider.proxy_spiders.KuaiSpider',
	'core.proxy_spider.proxy_spiders.ProxylistplusSpider',
	'core.proxy_spider.proxy_spiders.XiciSpider',
]

# 运行爬虫时间间隔,间隔2h
RUN_SPIDERS_INTERVAL = 2

# 配置检测代理IP的异步数量
TETS_PROXIES_ASYNC_COUNT = 10
# 配置检测代理IP的时间间隔
TETS_PROXIES_INTERVAL = 1
# 获取代理IP的最大数量,这个值越小可用性越高,随机性越差
PROXIES_MAX_COUNT = 20
# main.py
#!/usr/bin/env python

# -*- encoding: utf-8 -*-

'''
@Author  :   {Jack Zhao}

@Time    :   2020/5/9 8:47

@Contact :   {zc_dlmu@163.com}

@Desc    :  统一入口,开启三个进程,分别用于启动爬虫,检测代理和web服务统一
'''
from multiprocessing import Process

from core.proxy_spider.run_spiders import RunSpider
from core.proxy_test import ProxyTester
from core.proxy_api import ProxyApi


def run():
	'''
	定义列表,用于存储要启动的进程,然后将进程添加到列表中
	'''
	process_list = []
	process_list.append(Process(target=RunSpider.start))
	process_list.append(Process(target=ProxyTester.start))
	process_list.append(Process(target=ProxyApi.start))
	# 遍历进程列表,启动进程
	for process in process_list:
		# 最好设置守护进程,不会相互等待
		process.daemon = True
		process.start()

	# 遍历进程列表,让主进程等待子进程完成
	for process in process_list:
		process.join()


if __name__ == '__main__':
	run()

三、项目结果展示

3.1 数据库展示

3.2 Web页面展示(三种,挑选了一个展示)

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服