一个python爬虫工具类
写了一个爬虫工具类。
# -*- coding: utf-8 -*-
# @Time : 2018/8/7 16:29
# @Author : cxa
# @File : utils.py
# @Software: PyCharm
from retrying import retry
from decorators.decorators import decorator, parse_decorator
from glom import glom
from config import headers
import datetime
import hashlib
from tomorrow import threads
from requests_html import HTMLSession
try:
import simplejson as json
except ImportError:
import json
class MetaSingleton(type):
_inst = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._inst:
cls._inst[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
return cls._inst[cls]
class Get_Proxies(metaclass=MetaSingleton):
ip = None
def getproxy(self, change_proxy):
if self.ip is None:
self.ip = self.get_ip(HTMLSession())
self.proxies = {
'http': self.ip,
'https': self.ip
}
if change_proxy:
self.ip = self.get_ip(HTMLSession())
self.proxies = {
'http': self.ip,
'https': self.ip
}
return self.proxies
def get_ip(self, session):
url = 'ip'
req = session.get(url)
if req.status_code == 200:
jsonstr = req.json()
isok = glom(jsonstr, "resCode")
if isok == "0000":
key = glom(jsonstr, ('reData', ['key']))[0]
uname = glom(jsonstr, ('reData', ['username']))[0]
passwd = glom(jsonstr, ('reData', ['password']))[0]
proxies = f"http://{uname}:{passwd}@{key}"
return proxies
@retry(stop_max_attempt_number=5, wait_random_min=3000, wait_random_max=7000)
@decorator
def post_html(session, post_url: int, post_data: dict, headers=headers, timeout=30):
'''
:param session: 传入session对象
:param post_url: post请求需要的url
:param headers: 报头信息,config模块默认提供
:param post_data: post信息 字典类型
:param timeout:
:return:
'''
post_req = session.post(url=post_url, headers=headers, data=post_data, timeout=timeout, proxies=get_proxies())
if post_req.status_code == 200:
post_req.encoding = post_req.apparent_encoding
# time.sleep(random.randint(1, 3))
return post_req
# 随机等待1-3s
@retry(stop_max_attempt_number=5, wait_random_min=3000, wait_random_max=7000)
@decorator
def get_response(session, url: str, params=None, headers=headers, timeout=10):
'''
获取response
:param url:链接
:return: return response object
'''
try:
req = session.get(url=url, headers=headers, params=params, timeout=timeout, proxies=get_proxies())
except:
req = session.get(url=url, headers=headers, params=params, timeout=timeout, proxies=get_proxies(True))
if req.status_code == 200:
req.encoding = req.apparent_encoding
# time.sleep(random.randint(1, 3))
return req
# 随机等待1-3s
@decorator
def get_html(req):
'''
获取html类型的网页格式
:param req:
:return:
'''
source = req.text
return source
@decorator
def get_json(req):
'''
获取json类型的网页格式
:param req: response对象
:return:
'''
try:
jsonstr = req.json()
except:
source = get_html(req)
if source.endswith(';'):
jsonstr = json.loads(source.replace(';', ''))
return jsonstr
@parse_decorator(None)
def get_xpath(req, xpathstr: str):
'''
xpath操作获取节点
:param req:response对象
:param xpathstr:
:return:
'''
node = req.html.xpath(xpathstr)
return node
@decorator
def get_link(node):
'''
获取当前节点的链接
:param req:response对象
:return:返回绝对链接
'''
return list(node.absolute_links)[0]
@parse_decorator(None)
def get_text(node):
'''
获取当前节点下的文本
:param req:response对象
:param xpathstr:xpath表达式
:return:
'''
return node.text
@parse_decorator(None)
def get_all_text(node):
'''
获取该节点包括其子节点下的所有文本
:param req:response对象
:param xpathstr:xpath表达式
:return:
'''
if isinstance(node, list):
return node[0].full_text
else:
return node.full_text
@decorator
def get_json_data(jsonstr: str, pat: str):
'''
#通过glom模块操作数据
:param jsonstr:json字符串
:param pat:模板
:return:
'''
item = glom(jsonstr, pat)
return item
@decorator
def get_hash_code(key):
'''
获取字符串hash值,md5加密
:param key:
:return:
'''
value = hashlib.md5(key.encode('utf-8')).hexdigest()
return value
@parse_decorator(None)
def get_next_node(node, xpathstr):
'''
当前节点下面操作xpath
:param node: 节点
:param xpathstr: xpath表达式
:return:
'''
next_node = node[0].xpath(xpathstr)
if next_node:
return next_node
@decorator
def get_datetime_from_unix(unix_time):
'''
时间戳转时间格式
:param unix_time:
:return:
'''
unix_time_value = unix_time
if not isinstance(unix_time_value, int):
unix_time_value = int(unix_time)
new_datetime = datetime.datetime.fromtimestamp(unix_time_value)
return new_datetime
def get_proxies(change_proxy=False):
ip = Get_Proxies().getproxy(change_proxy)
return ip
@decorator
@threads(20)
@retry(stop_max_attempt_number=5)
def async_get_response(session, url: str, headers=headers, timeout=10):
'''
获取response
:param url:链接
:return: return response object
'''
try:
req = session.get(url=url, headers=headers, timeout=timeout, proxies=get_proxies())
except:
req = session.get(url=url, headers=headers, timeout=timeout, proxies=get_proxies(True))
# if req.status_code==200:
# req.encoding=req.apparent_encoding
# #time.sleep(random.randint(1, 3))
return req
if __name__ == '__main__':
print(get_proxies())
以下是headers文件的内容
import random
first_num = random.randint(55, 62)
third_num = random.randint(0, 3200)
fourth_num = random.randint(0, 140)
class FakeChromeUA:
os_type = [
'(Windows NT 6.1; WOW64)', '(Windows NT 10.0; WOW64)', '(X11; Linux x86_64)',
'(Macintosh; Intel Mac OS X 10_12_6)'
]
chrome_version = 'Chrome/{}.0.{}.{}'.format(first_num, third_num, fourth_num)
@classmethod
def get_ua(cls):
return ' '.join(['Mozilla/5.0', random.choice(cls.os_type), 'AppleWebKit/537.36',
'(KHTML, like Gecko)', cls.chrome_version, 'Safari/537.36']
)
headers = {
'User-Agent': FakeChromeUA.get_ua(),
'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Connection': 'keep-alive'
}
以下是logger文件的内容
# -*- coding: utf-8 -*-
import os
import time
import logging
import sys
log_dir1=os.path.join(os.path.dirname(os.path.dirname(__file__)),"logs")
today = time.strftime('%Y%m%d', time.localtime(time.time()))
full_path=os.path.join(log_dir1,today)
if not os.path.exists(full_path):
os.makedirs(full_path)
log_path=os.path.join(full_path,"t.log")
def get_logger():
# 获取logger实例,如果参数为空则返回root logger
logger = logging.getLogger("t")
if not logger.handlers:
# 指定logger输出格式
formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s')
# 文件日志
file_handler = logging.FileHandler(log_path,encoding="utf8")
file_handler.setFormatter(formatter) # 可以通过setFormatter指定输出格式
# 控制台日志
console_handler = logging.StreamHandler(sys.stdout)
console_handler.formatter = formatter # 也可以直接给formatter赋值
# 为logger添加的日志处理器
logger.addHandler(file_handler)
logger.addHandler(console_handler)
# 指定日志的最低输出级别,默认为WARN级别
logger.setLevel(logging.INFO)
# 添加下面一句,在记录日志之后移除句柄
return logger
一个python爬虫工具类的更多相关文章
- python爬虫工具集合
python爬虫工具集合 大家一起来整理吧!强烈建议PR.这是初稿,总是有很多问题,而且考虑不全面,希望大家支持! 源文件 主要针对python3 常用库 urllib Urllib是python提供 ...
- 常见Python爬虫工具总结
常见Python爬虫工具总结 前言 以前写爬虫都是用requests包,虽然很好用,不过还是要封装一些header啊什么的,也没有用过无头浏览器,今天偶然接触了一下. 原因是在处理一个错误的时候,用到 ...
- 免费IP代理池定时维护,封装通用爬虫工具类每次随机更新IP代理池跟UserAgent池,并制作简易流量爬虫
前言 我们之前的爬虫都是模拟成浏览器后直接爬取,并没有动态设置IP代理以及UserAgent标识,本文记录免费IP代理池定时维护,封装通用爬虫工具类每次随机更新IP代理池跟UserAgent池,并制作 ...
- Android 分享一个SharedPreferences的工具类,方便保存数据
我们平常保存一些数据,都会用到SharedPreferences,他是保存在手机里面的,具体路径是data/data/你的包名/shared_prefs/保存的文件名.xml, SharedPrefe ...
- 一个python爬虫小程序
起因 深夜忽然想下载一点电子书来扩充一下kindle,就想起来python学得太浅,什么“装饰器”啊.“多线程”啊都没有学到. 想到廖雪峰大神的python教程很经典.很著名.就想找找有木有pdf版的 ...
- MinerUtil.java 爬虫工具类
MinerUtil.java 爬虫工具类 package com.iteye.injavawetrust.miner; import java.io.File; import java.io.File ...
- Python数据库工具类MySQLdb使用
MySQLdb模块用于连接mysql数据库. 基本操作 # -*- coding: utf-8 -*- #mysqldb import time, MySQLdb ...
- 我的第一个Python爬虫——谈心得
2019年3月27日,继开学到现在以来,开了软件工程和信息系统设计,想来想去也没什么好的题目,干脆就想弄一个实用点的,于是产生了做“学生服务系统”想法.相信各大高校应该都有本校APP或超级课程表之类的 ...
- python爬虫工具
一直都听说python写爬虫工具非常方便,为了获取数据,我也要写点爬虫,但是python太灵活了,不知道python爬虫要哪些框架,要了解,比如beatiful soup,scrapy, 爬虫的额主要 ...
随机推荐
- C#使用 SharpSSH
准备试一把监控Linux机器 . 附件如下 :http://files.cnblogs.com/files/lclblog/Tamir.SharpSsh.zip
- AtCoder Grand Contest 019 A: Ice Tea Store
tourist出的题诶!想想就很高明,老年选手可能做不太动.不过A题还是按照惯例放水的. AtCoder Grand Contest 019 A: Ice Tea Store 题意:买0.25L,0. ...
- Eclipse 保存代码时,不自动换行设置
Eclipse在保存代码时,总是自动换行.尤其是注释,换行后的注释读起来就很混乱.后来发现是在保存文件时设置了自动格式化代码的原因. 关闭自动格式代码设置: windows-->Preferen ...
- 【数据库_Mysql】Mysql知识汇总
1.将多列字段合并显示用CONCAT(XX,XX,...): 2.查询表中某字段重复的数据: 查重复字段:select 字段 from table group by 字段 having count(* ...
- openstack的网络配置
首先在浏览器输入咱们的控制节点的ip地址登陆horizon,也就是dashboard控制页面 输入好用户名与密码,这时输入的用户名与密码会与我们的老大哥keystone进行认证.确认你输入的这个用户有 ...
- BZOJ4887 Tjoi2017可乐(动态规划+矩阵快速幂)
设f[i][j]为第i天到达j号城市的方案数,转移显然,答案即为每天在每个点的方案数之和.矩乘一发即可. #include<iostream> #include<cstdio> ...
- 【比赛】HNOI2018 寻宝游戏
考试的时候就拿了30points滚粗了 听说myy对这题的倒推做法很无奈,官方题解在此 正解思路真的很巧妙,也说的很清楚了 就是分别考虑每一位,会发现题解中的那个性质,然后把询问的二进制数按照排序后的 ...
- 关于Centos的yum安装LAMP
Step1.配置网易的源 在mirrors.163.com中找到centos的帮助信息,完成源的更新配置,如图1,图2,图3所示. 图1 图2 图3 Step2.然后安装PHP+MySQL+apach ...
- NOIP2017 考前汇总
时隔一年,相比去年一无所知的自己,学到了不少东西,虽然还是很弱,但也颇有收获[学会了打板QAQ] 现在是2017.11.9 21:10,NOIP2017的前两天晚上,明天就要出发,做最后的总结 N ...
- 洛谷 P3648 [APIO2014]序列分割 解题报告
P3648 [APIO2014]序列分割 题目描述 你正在玩一个关于长度为\(n\)的非负整数序列的游戏.这个游戏中你需要把序列分成\(k+1\)个非空的块.为了得到\(k+1\)块,你需要重复下面的 ...