首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Python爬虫入门教程 47-100 mitmproxy安装与安卓模拟器的配合使用-手机APP爬虫部分

1. 准备下载软件 介绍一款爬虫辅助工具mitmproxy ,mitmproxy 就是用于MITM的proxy,MITM中间人攻击。说白了就是服务器和客户机中间通讯多增加了一层。跟Fiddler和Charles最大的不同就是,mitmproxy可以进行二次开发,尤其可以对接python。 mitmproxy一般用于开发或者测试,用在爬虫辅助也是极好的。 1.1 几个重要地址 github地址:https://github.com/mitmproxy/mitmproxy官网地址:https://mitmproxy.org/ 1.2 安装流程 进入CMD窗口,执行 pip install mitmproxy 安装完成后,系统将拥有 mitmproxy、mitmdump、mitmweb 三个命令,由于 mitmproxy 命令不支持在 windo

优秀的个人博客,低调大师

从统计到概率,入门者都能用Python试验的机器学习基础 CDA数据分析师 4天前

要学习统计,就不可避免得先了解概率问题。概率涉及诸多公式和理论,容易让人迷失其中,但它在工作和日常生活中都具有重要作用。先前我们已经讨论过描述性统计中的一些基本概念,现在,我们将探讨统计和概率的关系。 前提条件: 与上一篇博客类似,本文不要求读者具备统计知识,但至少要对 Python 有一个基本的了解。考虑到读者可能不太了解 for 循环和列表, 下面将先对它们做个简单的介绍。 什么是概率? 从最基本的层面上来说,概率要回答的是一个这样的问题:「一个事件发生的几率是多少?」为了计算某个事件发生的几率,我们还要考虑其它所有可能发生的事件。 概率问题的典型代表是扔硬币。在扔硬币的过程中,只会产生两种结果: 1. 正面朝上 2. 反面朝上 这两种结果构成了一个样本空间,即所有可能结果的集合。为了计算一个事件发生的概率,我们要统计该事件发生(比如将硬币掷为正面朝上)的次数,并用它除以总试验次数。因此,概率会告诉我们,把一枚硬币掷为正面朝上或反面朝上的几率为 1/2。通过观察可能发生的事件,概率可以为我们提供一个预测事件发生频率的框架。 然而,即使结果看起来很明显,但如果我们真的试着去扔一些硬币,我们很可能得到过高或过低的正面朝上概率。假设扔硬币的做法不公平,那我们能做什么?收集数据!我们可以使用统计法来计算基于真实世界观察样本的概率,并将其与理想中的概率做对比。 从统计到概率 通过扔 10 次硬币并计算正面朝上的次数,我们可以获得数据。我们把这 10 次扔硬币的过程当做试验,而硬币正面朝上的次数将是数据点。也许正面朝上的次数不是「理想的」5 次,但不必着急,因为一次试验只是一个数据点。 如果进行多次试验,那我们预计所有试验正面朝上的的平均概率将接近 50%。下面的代码分别模拟了 10 次、100 次、1000 次和 1000000 次试验,然后计算了正面朝上的平均频率。下图是对这一过程的总结。 import random def coin_trial(): heads = 0 for i in range(100): if random.random() <= 0.5: heads +=1 return heads def simulate(n): trials = [] for i in range(n): trials.append(coin_trial()) return(sum(trials)/n) simulate(10) >> 5.4 simulate(100) >>> 4.83 simulate(1000) >>> 5.055 simulate(1000000) >>> 4.999781 coin_trial 函数代表了 10 次硬币投掷的模拟。它使用 random() 函数来生成一个介于 0 和 1 之间的随机浮点数,如果浮点数在 0.5 以下,它会增加 heads(正面朝上)次数。然后,simulate 根据你想要的次数来重复这些试验,并返回所有试验后正面朝上的平均次数。 硬币投掷模拟的结果很有趣。首先,模拟的数据显示正面朝上的平均次数接近概率估计的结果。其次,随着试验次数的增加,这个 平均数也更加接近预期结果。做 10 次模拟时,有轻微的误差,但试验次数为 1000000 次时,误差几乎完全消失。随着我们增加试验次数,与预期平均数的偏差在不断减小。听起来很耳熟是不是? 当然,我们可以自己扔硬币,但是通过在 Python 代码中模拟这一过程可以为节省大量时间。随着我们获得越来越多的数据,现实世界(结果)开始与理想世界(预期)重合。因此,给定足够的数据,统计就可以让我们根据现实世界的观察来估计概率。概率提供了理论,而统计提供了使用数据来检验该理论的工具。于是,统计样本的数值特征,特别是均值和标准差,成为了理论的替代。 你可能会问:「如果我本来就可以计算理论概率,那我为什么还要用一个替代品?」投掷硬币是一个非常简单的例子,但有些更有趣的概率问题并没有这么容易计算。随着时间的推移,一个人患病的可能性有多大?当你开车时,一个关键的汽车部件出故障的概率是多少? 计算概率没有什么简单的方法,所以我们必须依靠数据和统计。给定更多的数据,我们的结果有更多的置信度,确信计算结果代表了这些重要事件发生的真实概率。 假设我是一名在职侍酒师,购买之前,我要先弄清楚哪些葡萄酒品质更优。我手头已有很多数据,所以我们将使用统计数据来指导决策。 数据和分布 在解决「哪种葡萄酒更好」的问题之前,我们需要注意数据的性质。直观来说,我们想通过打分来选出比较好的葡萄酒,但问题是:分数通常分布在一个范围内。那我们要如何比较不同类型葡萄酒的得分,并在一定程度上确定一种葡萄酒比另一种更好呢? 若有一个正态分布(也称为高斯分布),它是概率和统计领域中一个特别重要的现象。正态分布如下所示: 正态分布最重要的特质是对称性和形状,以及其广泛的普适性。我们一直称其为分布,但是分布的到底是什么?我们可以直观地认为概率分布是一个任务中所有可能存在的事件及其对应的概率,例如在「抛硬币」任务中,「正面」和「反面」两个事件,以及它们对应出现的概率 1/2 可以组成一个分布。 在概率中,正态分布是所有事件及对应概率的特定分布。x 轴表示我们想知道概率的事件,y 轴是与每个事件相关联的概率——从 0-1。在这里,我们没有深入讨论概率分布,但是知道正态分布是一种特别重要的概率分布。 在统计中,正态分布是数据值的分布。在这里,x 轴是数据的值,y 轴是这些值的计数。以下是两张相同的正态分布图,但是根据概率和统计来进行标记: 在概率的正态分布中,最高点表示发生概率最大的事件。离这个事件越远,概率下降越厉害,最后形成一个钟的形状。而在统计的正态分布中,最高点代表均值,与概率中的情况类似,离均值越远,频率下降越厉害。也就是说,两端的点与均值存在极高的偏差,且样本非常罕见。 如果你通过正态分布怀疑概率和统计之间存在另一种关系,那么你没猜错!我们将在本文后面探讨这种重要关系,先别着急。 既然打算用质量分数的分布来比较不同的葡萄酒,我们需要设置一些条件来搜索感兴趣的葡萄酒。我们将收集葡萄酒的数据,然后分离出一些感兴趣的葡萄酒质量分数。 为了取得数据,我们需要以下代码: import csv with open("wine-data.csv", "r", encoding="latin-1") as f: wines = list(csv.reader(f)) 数据以表格形式显示在下面。我们需要 points 列,所以我们将把它提取到自己的列表中。一位葡萄酒专家告诉我们匈牙利的托卡伊白葡萄酒非常棒,而一位朋友则建议我们以意大利的蓝布鲁斯科红葡萄酒开始入手。我们可以用数据来比较这些葡萄酒! 如果你不记得数据是什么样子的,下面有一个简要的表格供你参考和重新了解。 # Extract the Tokaji scores tokaji = [] non_tokaji = [] for wine in wines: if points != '': points = wine[4] if wine[9] == "Tokaji": tokaji.append(float(points)) else: non_tokaji.append(points) # Extract the Lambrusco scores lambrusco = [] non_lambrusco = [] for wine in wines: if points != '': points = wine[4] if wine[9] == "Lambrusco": lambrusco.append(float(points)) else: non_lambrusco.append(float(points)) 如果把每组质量分数可视化为正态分布,我们可以根据它们所处的位置立即判断两种分布是否相同,但如下所示用这种方法很快会遇到问题。因为我们有大量数据,所以假设分数会呈正态分布。虽然这种假设在这里没问题,但实际上这么做很危险,这点将在稍后讨论。 当两个分数分布重叠太多时,最好假设你的分数是来自同一个而非不同的分布。在另一种极端即两个分布没有重叠的情况下,可以安全地假设它们来自不同的分布。麻烦在于有些重叠的情况比较特殊。例如,一个分布的极高点可能与另一个分布的极低点相交,这种情况下我们该如何判断这些分数是否来自不同的分布。 因此,我们再次期望正态分布可以给我们一个答案,并在统计学和概率之间架起一座桥梁。 重新审视正态分布 正态分布对概率和统计学来说至关重要,原因有二:中心极限定理和 3σ 准则。 中心极限定理 在上一节中,我们展示了如果把掷硬币的试验重复十次,正面朝上的平均结果将接近理想的 50%。随着试验次数的增加,平均结果会越接近真实概率,即使个别试验本身并不完美。这种想法或数学上称为依概收敛就是中心极限定理的一个关键原则。 在掷硬币的例子中,一次试验扔 10 次硬币,我们会估计每次试验正面朝上的次数为 5。之所以是估计,是因为我们知道结果并没有那么完美(即,不会每次都得到 5 次正面朝上的结果)。如果我们做出很多估计,根据中心极限定理,这些估计的分布将看起来像正态分布,这种分布的顶点或估计值的期望将与真实值一致。我们观察到,在统计学中正态分布的顶点与平均值一致。因此,给定多次「试验」作为数据,中心极限定理表明,即使我们不知道真正的概率,我们也可以通过数据估计出分布可能的形状。 中心极限定理让我们知道多次试验的平均值将接近真实平均值,而 3σ准则将告诉我们有多少数据将围绕这个平均值分布。 3σ 准则 3σ 准则(也被称为经验法则或 68-95-99.7 法则),是我们观察到有多少数据落在平均值某一距离内的一种表达。注意,标准差(又名「sigma」)是数据观测值与平均值之间的平均距离。 3σ 准则规定,给定正态分布,68% 的观测值将落在平均值的一个标准差之间,95% 将落在两个标准差以内,99.7% 将落在三个标准差以内。很多复杂的数学都涉及这些值的推导,因此,具体不在本文的讨论范围之内。关键是要知道,3σ 准则使我们能够了解正态分布的不同区间内分别包含了多少数据。下图是对 3σ 准则所代表内容的总结。 我们将把这些概念与葡萄酒数据联系起来。根据假设,作为一个品酒师,我们想知道与普通葡萄酒相比,霞多丽白葡萄酒和黑皮诺葡萄酒更受欢迎的程度。我们收集了成千上万条关于葡萄酒的评论,而根据中心极限定理,这些评论的平均分数应该与葡萄酒质量(由评论者判断)的「真实」表征一致。 虽然 3σ 准则说明了你的数据有多少在已知值范围内,但它也说明了极端值的罕见性。任何偏离平均值三个标准差的值都应小心处理。通过 3σ准则和 Z-score,我们最终可以通过数值度量霞多丽白葡萄酒、黑皮诺葡萄酒与普通葡萄酒的区别程度。 Z-score Z-score 是一个简单的计算,它回答了这样一个问题:「给定一个数据点,它离平均值有多少标准差?」下面是 Z-score 方程: Z-score 本身并没有给你提供很多少信息。但当与一个 Z-table 比较时,它就非常有价值,该表列出了一个标准正态分布的累积概率,直到给定 Z-score。标准正态分布是平均值为 0、标准差为 1 的正态分布。即使我们的正态分布不是标准的,Z-score 也允许我们参考 Z-table。 累积概率(或称为概率分布函数)是给定点出现之前所有值的概率之和。一个简单的例子是平均值本身。平均值是正态分布的正中间部分,所以我们知道从左向右取值到平均值的所有概率之和为 50%。如果你想计算标准差之间的累计概率,3σ准则的值实际上会出现。下图是累积概率的可视化图。 所有概率之和必须等于 100%,所以我们用 Z-table 来计算正态分布下 Z-score 两边的概率。 这种超过某个 Z-score 的概率计算对我们很有用。它让我们从「一个值离平均值有多远?」的问题升级到「一个值与同一组观测值的平均值相差特定距离的可能性有多大?」因此,从 Z-score 和 Z-table 得出的概率将回答我们关于葡萄酒的问题。 import numpy as np tokaji_avg = np.average(tokaji) lambrusco_avg = np.average(lambrusco) tokaji_std = np.std(tokaji) lambrusco = np.std(lambrusco) # Let's see what the results are print("Tokaji: ", tokaji_avg, tokaji_std) print("Lambrusco: ", lambrusco_avg, lambrusco_std) >>> Tokaji: 90.9 2.65015722804 >>> Lambrusco: 84.4047619048 1.61922267961 看起来朋友的推荐并不是很好!为了本文的目的,我们把托卡伊白葡萄酒和蓝布鲁斯科红葡萄酒的分数都视为正态分布。因此,每种葡萄酒的平均分数将代表它们在质量方面的「真实」分数。我们将计算 Z-score,看看托卡伊白葡萄酒的平均值与蓝布鲁斯科红葡萄酒的平均值相差多少。 z = (tokaji_avg - lambrusco_avg) / lambrusco_std >>> 4.0113309781438229 # We'll bring in scipy to do the calculation of probability from the Z-table import scipy.stats as st st.norm.cdf(z) >>> 0.99996981130231266 # We need the probability from the right side, so we'll flip it! 1 - st.norm.cdf(z) >>> 3.0188697687338895e-05 答案是差距很小。但这到底意味着什么?这种概率的无穷小量可能需要详细解释。 假设托卡伊白葡萄酒和蓝布鲁斯科红葡萄酒的质量没有什么差别。也就是说,二者的品质差不多。同样,由于葡萄酒之间的个体差异,这些葡萄酒的分数会有一些分散。根据中心极限定理,如果我们制作这两种葡萄酒分数的直方图,将会产生服从正态分布的质量分数。 现在,我们可以利用一些数据计算出这两种葡萄酒的平均值和标准差。这些值可以检验它们的品质是否相似。我们将使用蓝布鲁斯科红葡萄酒分数作为基础,并比较了托卡伊白葡萄酒的平均分数,反过来做也很简单。唯一不同的是负 Z-score。 Z-score 为 4.01!假设托卡伊和蓝布鲁斯科的品质相似,根据 3σ准则,99.7% 的数据应该在 3 个标准差范围内。在托卡伊和蓝布鲁斯科被视为品质相同的情况下,远离质量分数平均值的概率非常非常小。这种概率如此之小,以至于我们不得不考虑相反的情况:如果托卡伊不同于蓝布鲁斯科,将会产生不同的分数分布。 此处我们仔细选择了措辞:我没有说「托卡伊比蓝布鲁斯科好」。因为我们计算了这种概率,虽然微观上很小,但不是零。确切地,可以说托卡伊和蓝布鲁斯科绝对不是来自同一个分布,但不能就此说其中一种比另一种更好或更差。 这种推理属于推理统计的范畴,而本文只想做一个简单的介绍。本文介绍了很多概念,所以如果你觉得有些头疼,不妨回头慢慢看。 总结 我们从描述性统计开始,然后将其与概率联系起来。根据概率,我们开发了一种定量显示两组分数是否来自同一分布的方法。根据这种方法,我们比较了别人推荐的两种葡萄酒,发现它们很可能来自不相同的质量分数分布。也就是说,一种葡萄酒很可能比另一种更好。 统计不是只属于统计学家的领域,作为一名数据科学家,对常用的统计方法有一个直观的理解将有助于你构建自己的理论,以及随后测试这些理论的能力。在这里我们几乎没有触及推理统计,但是同样的想法将有助于指导理解统计原理。本文讨论了正态分布的优点,但是统计学家也开发了非正态分布的技术。 原文发布时间为:2018-09-21 本文来自云栖社区合作伙伴“CDA数据分析师”,了解相关信息可以关注“CDA数据分析师”。

优秀的个人博客,低调大师

Hadoop MapReduce编程 API入门系列之自定义多种输入格式数据类型和排序多种输出格式(十一)

自定义输入格式,将明星微博数据排序后按粉丝数 关注数 微博数 分别输出到不同文件中。 代码 1 package zhouls.bigdata.myMapReduce.ScoreCount; 2 3 import java.io.DataInput; 4 import java.io.DataOutput; 5 import java.io.IOException; 6 import org.apache.hadoop.io.WritableComparable; 7 /** 8 * 学习成绩读写类 9 * 数据格式参考:19020090017 小讲 90 99 100 89 95 10 * @author Bertron 11 * 需要自定义一个 ScoreWritable 类实现 WritableComparable 接口,将学生各门成绩封装起来。 12 */ 13 public class ScoreWritable implements WritableComparable< Object > {//其实这里,跟TVPlayData一样的 14 // 注意: Hadoop通过Writable接口实现的序列化机制,不过没有提供比较功能,所以和java中的Comparable接口合并,提供一个接口WritableComparable。(自定义比较) 15 // Writable接口提供两个方法(write和readFields)。 16 17 18 private float Chinese; 19 private float Math; 20 private float English; 21 private float Physics; 22 private float Chemistry; 23 24 25 // 问:这里我们自己编程时,是一定要创建一个带有参的构造方法,为什么还要显式的写出来一个带无参的构造方法呢? 26 // 答:构造器其实就是构造对象实例的方法,无参数的构造方法是默认的,但是如果你创造了一个带有参数的构造方法,那么无参的构造方法必须显式的写出来,否则会编译失败。 27 28 public ScoreWritable(){}//java里的无参构造函数,是用来在创建对象时初始化对象 29 //在hadoop的每个自定义类型代码里,好比,现在的ScoreWritable,都必须要写无参构造函数。 30 31 32 //问:为什么我们在编程的时候,需要创建一个带有参的构造方法? 33 //答:就是能让赋值更灵活。构造一般就是初始化数值,你不想别人用你这个类的时候每次实例化都能用另一个构造动态初始化一些信息么(当然没有需要额外赋值就用默认的)。 34 35 public ScoreWritable(float Chinese,float Math,float English,float Physics,float Chemistry){//java里的有参构造函数,是用来在创建对象时初始化对象 36 this.Chinese = Chinese; 37 this.Math = Math; 38 this.English = English; 39 this.Physics = Physics; 40 this.Chemistry = Chemistry; 41 } 42 43 //问:其实set和get方法,这两个方法只是类中的setxxx和getxxx方法的总称, 44 // 那么,为什么在编程时,有set和set***两个,只有get***一个呢? 45 46 public void set(float Chinese,float Math,float English,float Physics,float Chemistry){ 47 this.Chinese = Chinese;//即float Chinese赋值给private float Chinese; 48 this.Math = Math; 49 this.English = English; 50 this.Physics = Physics; 51 this.Chemistry = Chemistry; 52 } 53 // public float get(float Chinese,float Math,float English,float Physics,float Chemistry){因为这是错误的,所以对于set可以分开,get只能是get*** 54 // return Chinese; 55 // return Math; 56 // return English; 57 // return Physics; 58 // return Chemistry; 59 // } 60 61 62 public float getChinese() {//拿值,得返回,所以需有返回类型float 63 return Chinese; 64 } 65 public void setChinese(float Chinese){//设值,不需,所以空返回类型 66 this.Chinese = Chinese; 67 } 68 public float getMath() {//拿值 69 return Math; 70 } 71 public void setMath(float Math){//设值 72 this.Math = Math; 73 } 74 public float getEnglish() {//拿值 75 return English; 76 } 77 public void setEnglish(float English){//设值 78 this.English = English; 79 } 80 public float getPhysics() {//拿值 81 return Physics; 82 } 83 public void setPhysics(float Physics){//设值 84 this.Physics = Physics; 85 } 86 public float getChemistry() {//拿值 87 return Chemistry; 88 } 89 public void setChemistry(float Chemistry) {//拿值 90 this.Chemistry = Chemistry; 91 } 92 93 // 实现WritableComparable的readFields()方法 94 // 对象不能传输的,需要转化成字节流! 95 // 将对象转换为字节流并写入到输出流out中是序列化,write 的过程(最好记!!!) 96 // 从输入流in中读取字节流反序列化为对象 是反序列化,readFields的过程(最好记!!!) 97 public void readFields(DataInput in) throws IOException {//拿代码来说的话,对象就是比如Chinese、Math。。。。 98 Chinese = in.readFloat();//因为,我们这里的对象是float类型,所以是readFloat() 99 Math = in.readFloat(); 100 English = in.readFloat();//注意:反序列化里,需要生成对象对吧,所以,是用到的是get那边对象 101 Physics = in.readFloat(); 102 Chemistry = in.readFloat(); 103 // in.readByte() 104 // in.readChar() 105 // in.readDouble() 106 // in.readLine() 107 // in.readFloat() 108 // in.readLong() 109 // in.readShort() 110 } 111 112 // 实现WritableComparable的write()方法,以便该数据能被序列化后完成网络传输或文件输出 113 // 将对象转换为字节流并写入到输出流out中是序列化,write 的过程(最好记!!!) 114 // 从输入流in中读取字节流反序列化为对象 是反序列化,readFields的过程(最好记!!!) 115 public void write(DataOutput out) throws IOException {//拿代码来说的话,对象就是比如Chinese、Math。。。。 116 out.writeFloat(Chinese);//因为,我们这里的对象是float类型,所以是writeFloat() 117 out.writeFloat(Math); 118 out.writeFloat(English);//注意:序列化里,需要对象对吧,所以,用到的是set那边的对象 119 out.writeFloat(Physics); 120 out.writeFloat(Chemistry); 121 // out.writeByte() 122 // out.writeChar() 123 // out.writeDouble() 124 // out.writeFloat() 125 // out.writeLong() 126 // out.writeShort() 127 // out.writeUTF() 128 } 129 130 public int compareTo(Object o) {//java里的比较,Java String.compareTo() 131 return 0; 132 } 133 134 135 // Hadoop中定义了两个序列化相关的接口:Writable 接口和 Comparable 接口,这两个接口可以合并成一个接口 WritableComparable。 136 // Writable 接口中定义了两个方法,分别为write(DataOutput out)和readFields(DataInput in) 137 // 所有实现了Comparable接口的对象都可以和自身相同类型的对象比较大小 138 139 140 // Hadoop中定义了两个序列化相关的接口:Writable 接口和 Comparable 接口,这两个接口可以合并成一个接口 WritableComparable。 141 // Writable 接口中定义了两个方法,分别为write(DataOutput out)和readFields(DataInput in) 142 // 所有实现了Comparable接口的对象都可以和自身相同类型的对象比较大小 143 144 145 // 源码是 146 // package java.lang; 147 // import java.util.*; 148 // public interface Comparable { 149 // /** 150 // * 将this对象和对象o进行比较,约定:返回负数为小于,零为大于,整数为大于 151 // */ 152 // public int compareTo(T o); 153 // } 154 155 } 1 package zhouls.bigdata.myMapReduce.WeiboCount; 2 3 import java.io.IOException; 4 5 import org.apache.hadoop.conf.Configuration; 6 import org.apache.hadoop.fs.FSDataInputStream; 7 import org.apache.hadoop.fs.FileSystem; 8 import org.apache.hadoop.fs.Path; 9 import org.apache.hadoop.io.Text; 10 import org.apache.hadoop.mapreduce.InputSplit; 11 import org.apache.hadoop.mapreduce.JobContext; 12 import org.apache.hadoop.mapreduce.RecordReader; 13 import org.apache.hadoop.mapreduce.TaskAttemptContext; 14 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 15 import org.apache.hadoop.mapreduce.lib.input.FileSplit; 16 import org.apache.hadoop.util.LineReader; 17 19 20 21 //其实这个程序,就是在实现InputFormat接口,TVPlayInputFormat是InputFormat接口的实现类 22 //比如 WeiboInputFormat extends FileInputFormat implements InputFormat。 23 24 //问:自定义输入格式 WeiboInputFormat 类,首先继承 FileInputFormat,然后分别重写 isSplitable() 方法和 createRecordReader() 方法。 25 26 27 public class WeiboInputFormat extends FileInputFormat<Text,WeiBo>{ 28 29 // 线路是: boolean isSplitable() -> RecordReader<Text,WeiBo> createRecordReader() -> WeiboRecordReader extends RecordReader<Text, WeiBo > 30 31 32 @Override 33 protected boolean isSplitable(JobContext context, Path filename) {//这是InputFormat的isSplitable方法 34 //isSplitable方法就是是否要切分文件,这个方法显示如果是压缩文件就不切分,非压缩文件就切分。 35 // 如果不允许分割,则isSplitable==false,则将第一个block、文件目录、开始位置为0,长度为整个文件的长度封装到一个InputSplit,加入splits中 36 // 如果文件长度不为0且支持分割,则isSplitable==true,获取block大小,默认是64MB 37 return false; //整个文件封装到一个InputSplit 38 //要么就是return true; //切分64MB大小的一块一块,再封装到InputSplit 39 } 40 41 42 43 44 @Override 45 public RecordReader<Text, WeiBo> createRecordReader(InputSplit arg0,TaskAttemptContext arg1) throws IOException, InterruptedException{ 46 // RecordReader<k1, v1>是返回类型,返回的RecordReader对象的封装 47 // createRecordReader是方法,在这里是,WeiboInputFormat.createRecordReader。WeiboInputFormat是InputFormat类的实例 48 // InputSplit input和TaskAttemptContext context是传入参数 49 50 // isSplitable(),如果是压缩文件就不切分,整个文件封装到一个InputSplit 51 // isSplitable(),如果是非压缩文件就切,切分64MB大小的一块一块,再封装到InputSplit 52 53 //这里默认是系统实现的的RecordReader,按行读取,下面我们自定义这个类WeiboRecordReader。 54 //类似与Excel、WeiBo、TVPlayData代码写法 55 return new WeiboRecordReader();//新建一个ScoreRecordReader实例,所有才有了上面RecordReader<Text,ScoreWritable>,所以才如下ScoreRecordReader,写我们自己的 56 } 57 58 59 60 public class WeiboRecordReader extends RecordReader<Text, WeiBo>{ 61 //LineReader in是1,行号。 62 //Text line; 俞灏明 俞灏明 10591367 206 558,每行的相关记录 63 public LineReader in;//行读取器 64 public Text line;//每行数据类型 65 public Text lineKey;//自定义key类型,即k1 66 public WeiBo lineValue;//自定义value类型,即v1 67 68 69 @Override 70 public void close() throws IOException {//关闭输入流 71 if(in !=null){ 72 in.close(); 73 } 74 } 75 @Override 76 public Text getCurrentKey() throws IOException, InterruptedException {//获取当前的key,即CurrentKey 77 return lineKey;//返回类型是Text,即Text lineKey 78 } 79 @Override 80 public WeiBo getCurrentValue() throws IOException,InterruptedException {//获取当前的Value,即CurrentValue 81 return lineValue;//返回类型是WeiBo,即WeiBo lineValue 82 } 83 @Override 84 public float getProgress() throws IOException, InterruptedException {//获取进程,即Progress 85 return 0;//返回类型是float,即float 0 86 } 87 88 89 90 @Override 91 public void initialize(InputSplit input, TaskAttemptContext context)throws IOException, InterruptedException{//初始化,都是模板 92 FileSplit split=(FileSplit)input;//获取split 93 Configuration job=context.getConfiguration(); 94 Path file=split.getPath();//得到文件路径 95 FileSystem fs=file.getFileSystem(job); 96 97 FSDataInputStream filein=fs.open(file);//打开文件 98 in=new LineReader(filein,job); //输入流in 99 line=new Text();//每行数据类型 100 lineKey=new Text();//自定义key类型,即k1。//新建一个Text实例作为自定义格式输入的key 101 lineValue = new WeiBo();//自定义value类型,即v1。//新建一个TVPlayData实例作为自定义格式输入的value 102 } 103 104 105 //此方法读取每行数据,完成自定义的key和value 106 @Override 107 public boolean nextKeyValue() throws IOException, InterruptedException{//这里面,才是篡改的重点 108 int linesize=in.readLine(line); //line是每行数据,我们这里用到的是in.readLine(str)这个构造函数,默认读完读到文件末尾。其实这里有三种。 109 110 // 是SplitLineReader.readLine -> SplitLineReader extends LineReader -> org.apache.hadoop.util.LineReader 111 112 // in.readLine(str)//这个构造方法执行时,会首先将value原来的值清空。默认读完读到文件末尾 113 // in.readLine(str, maxLineLength)//只读到maxLineLength行 114 // in.readLine(str, maxLineLength, maxBytesToConsume)//这个构造方法来实现不清空,前面读取的行的值 115 116 117 if(linesize==0) return false; 118 119 //通过分隔符'\t',将每行的数据解析成数组 pieces 120 String[] pieces = line.toString().split("\t"); 121 //因为,我们这里是。默认读完读到文件末尾。line是Text类型。pieces是String[],即String数组。 122 123 if(pieces.length != 5){ 124 throw new IOException("Invalid record received"); 125 } 126 127 int a,b,c; 128 129 try{ 130 a = Integer.parseInt(pieces[2].trim());//粉丝,//将String类型,如pieces[2]转换成,float类型,给a 131 b = Integer.parseInt(pieces[3].trim());//关注 132 c = Integer.parseInt(pieces[4].trim());//微博数 133 }catch(NumberFormatException nfe) 134 { 135 throw new IOException("Error parsing floating poing value in record"); 136 } 137 138 139 //自定义key和value值 140 lineKey.set(pieces[0]); //完成自定义key数据 141 lineValue.set(b, a, c);//完成自定义value数据 142 // 或者写 143 // lineValue.set(Integer.parseInt(pieces[2].trim()),Integer.parseInt(pieces[3].trim()),Integer.parseInt(pieces[4].trim())); 144 145 146 // pieces[0] pieces[1] pieces[2] ... pieces[4] 147 // 俞灏明 俞灏明 10591367 206 558 148 // 李敏镐 李敏镐 22898071 11 268 149 // 大自然保护协会-马云 大自然保护协会-马云 15616866 0 39 150 // 林心如 林心如 57488649 214 5940 151 // 时尚小编Anne 时尚小编Anne 10064227 136 2103 152 // 黄晓明 黄晓明 22616497 506 2011 153 // 张靓颖 张靓颖 27878708 238 3846 154 // 张成龙2012 张成龙2012 9813621 199 744 155 // 吳君如大美女 吳君如大美女 18490338 190 412 156 // 李娜 李娜 23309493 81 631 157 // 徐小平 徐小平 11659926 1929 13795 158 // 唐嫣 唐嫣 24301532 200 2391 159 // 有斐君 有斐君 8779383 577 4251 160 161 162 return true; 163 } 164 165 166 167 } 168 } 1 package zhouls.bigdata.myMapReduce.WeiboCount; 2 3 import java.io.IOException; 4 import java.util.Arrays; 5 import java.util.Comparator; 6 import java.util.HashMap; 7 import java.util.Set; 8 import java.util.Map; 9 10 import org.apache.hadoop.conf.Configuration; 11 import org.apache.hadoop.conf.Configured; 12 import org.apache.hadoop.fs.FileSystem; 13 import org.apache.hadoop.fs.Path; 14 15 import org.apache.hadoop.io.IntWritable; 16 import org.apache.hadoop.io.Text; 17 import org.apache.hadoop.mapreduce.Job; 18 import org.apache.hadoop.mapreduce.Mapper; 19 import org.apache.hadoop.mapreduce.Reducer; 20 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 21 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 22 import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs; 23 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; 24 import org.apache.hadoop.util.Tool; 25 import org.apache.hadoop.util.ToolRunner; 26 27 public class WeiboCount extends Configured implements Tool{ 28 public static class WeiBoMapper extends Mapper<Text, WeiBo, Text, Text>{ 29 @Override 30 protected void map(Text key, WeiBo value, Context context) throws IOException, InterruptedException{ 31 context.write(new Text("follower"),new Text(key.toString() + "\t" + value.getFollowers())); 32 context.write(new Text("friend"),new Text(key.toString() + "\t" + value.getFriends())); 33 context.write(new Text("statuses"),new Text(key.toString() + "\t" + value.getStatuses())); 34 } 35 } 36 37 public static class WeiBoReducer extends Reducer<Text, Text, Text, IntWritable> { 38 private MultipleOutputs<Text, IntWritable> mos; 39 40 protected void setup(Context context) throws IOException,InterruptedException{ 41 mos = new MultipleOutputs<Text, IntWritable>(context); 42 } 43 44 private Text text = new Text(); 45 46 protected void reduce(Text Key, Iterable<Text> Values,Context context) throws IOException, InterruptedException{ 47 int N = context.getConfiguration().getInt("reduceHasMaxLength", Integer.MAX_VALUE); 48 Map<String,Integer> m = new HashMap<String,Integer>(); 49 for(Text value:Values){//星型for循环,意思是把Values的值传给Text value 50 //value=名称+(粉丝数 或 关注数 或 微博数) 51 String[] records = value.toString().split("\t"); 52 m.put(records[0],Integer.parseInt(records[1].toString())); 53 } 54 55 //对Map内的数据进行排序 56 Map.Entry<String, Integer>[] entries = getSortedHashtableByValue(m); 57 for(int i = 0; i< N && i< entries.length;i++){ 58 if(Key.toString().equals("follower")){ 59 mos.write("follower",entries[i].getKey(), entries[i].getValue()); 60 }else if(Key.toString().equals("friend")){ 61 mos.write("friend", entries[i].getKey(), entries[i].getValue()); 62 }else if(Key.toString().equals("status")){ 63 mos.write("statuses", entries[i].getKey(), entries[i].getValue()); 64 } 65 } 66 } 67 68 protected void cleanup(Context context) throws IOException,InterruptedException { 69 mos.close(); 70 } 71 } 72 73 74 public int run(String[] args) throws Exception{ 75 Configuration conf = new Configuration();// 配置文件对象 76 Path mypath = new Path(args[1]); 77 FileSystem hdfs = mypath.getFileSystem(conf);// 创建输出路径 78 if (hdfs.isDirectory(mypath)){ 79 hdfs.delete(mypath, true); 80 } 81 82 Job job = new Job(conf, "weibo");// 构造任务 83 job.setJarByClass(WeiboCount.class);// 主类 84 85 job.setMapperClass(WeiBoMapper.class);// Mapper 86 job.setMapOutputKeyClass(Text.class);// Mapper key输出类型 87 job.setMapOutputValueClass(Text.class);// Mapper value输出类型 88 89 job.setReducerClass(WeiBoReducer.class);// Reducer 90 job.setOutputKeyClass(Text.class); 91 job.setOutputValueClass(IntWritable.class); 92 FileInputFormat.addInputPath(job, new Path(args[0]));// 输入路径 93 FileOutputFormat.setOutputPath(job, new Path(args[1]));// 输出路径 94 job.setInputFormatClass(WeiboInputFormat.class);// 自定义输入格式 95 //自定义文件输出类别 96 MultipleOutputs.addNamedOutput(job, "follower", TextOutputFormat.class,Text.class, IntWritable.class); 97 MultipleOutputs.addNamedOutput(job, "friend", TextOutputFormat.class,Text.class, IntWritable.class); 98 MultipleOutputs.addNamedOutput(job, "status", TextOutputFormat.class,Text.class, IntWritable.class); 99 job.waitForCompletion(true); 100 return 0; 101 } 102 103 104 //对Map内的数据进行排序(只适合小数据量) 105 public static Map.Entry[] getSortedHashtableByValue(Map h){ 106 Set set = h.entrySet(); 107 Map.Entry[] entries = (Map.Entry[]) set.toArray(new Map.Entry[set.size()]); 108 Arrays.sort(entries, new Comparator(){ 109 public int compare(Object arg0, Object arg1){ 110 Long key1 = Long.valueOf(((Map.Entry) arg0).getValue().toString()); 111 Long key2 = Long.valueOf(((Map.Entry) arg1).getValue().toString()); 112 return key2.compareTo(key1); 113 } }); 114 return entries; 115 } 116 117 public static void main(String[] args) throws Exception{ 118 // String[] args0 = { "hdfs://HadoopMaster:9000/weibo/weibo.txt", 119 // "hdfs://HadoopMaster:9000/out/weibo/" }; 120 121 String[] args0 = { "./data/weibo/weibo.txt", 122 "./out/weibo/" }; 123 124 int ec = ToolRunner.run(new Configuration(), new WeiboCount(), args0); 125 System.exit(ec); 126 } 127 } 128 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/6164435.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android NDK开发之入门示例 用C++ 写一个能四则运算的计算器

这回用Android的NDK技术写一个计算器练练手,啥是Android的NDK开发?看看Google的介绍--传送门 为啥要用NDK开发呢,NDK是用C++ 写的,运行效率特别高,在一些需要复杂计算的地方(例如游戏开发),还有就是Java代码反编译比较简单,很容易被反编译暴露源码,C++的反编译难度较大,涉及到加密的代码可以用C++来写。当然用NDK开发也有缺点,C++代码上手比Java难,而且用C++后调试难度增加,所以是否要引入C++要权衡之后再决定。 我在暑假用C++写了一个能四则运算的小程序,现在想在Android端也写一个支持四则运算的计算器,要是再用Java重写一遍就太麻烦了,正好可以用这个练一练Android的NDK开发。 工欲善其事必先利其器,还么有配置好NDK开发环境的可以看我上一篇文章--传送门; 环境配好了,话不多说,开始撸代码吧。新建一个项目, 新建项目.png 一定要把 Include C++ support 选中,然后 next,然后到选中Android版本,选择Activity的地方,都默认即可,一路 next。 到这还是默认就行,然后 finish,等项目创建成功后会看到熟悉的界面 和我们普通项目有点区别的地方是在 Activity的 onCreate方法中会多出一段代码和一个方法 static { System.loadLibrary("native-lib"); } public native String stringFromJNI(); 这段代码是用来加载C++生成的动态库,方法是一个本地方法,我理解为调用C++函数的方法。 先介绍到这,然后开始计算器界面的编写,这和普通的界面编写没有区别,就不多说了,上一个效果图吧 效果图 接下来就是Activity中的各种逻辑的编写,点击事件的处理,代码有点多,先不贴了,最后我会分享。 注意了,到这重点来了,要新建C++代码的源文件和头文件。在CPP文件夹上右键 New-> C++class,填写文件名-> OK。 你会发现在CPP目录下没有刚才新建的文件,我靠,AS出BUG了吧。不要急,在导航栏的最下边找到CMakeLists.text,点开,在图上标注的地方添加代码 CMakeLists.txt 在 src/main/cpp/native-lib.cpp 下面添加 src/main/cpp/×××××.cpp ××××是你的C++源文件的名。点击右上角的 Sync Now,等待同步完成。 这时你会发现CPP目录下有多了两个文件 CPP 这时回到 MainActivity 中,把 public native String stringFromJNI();方法修改一下。改成这样 public native double stringFromC(String s);。为啥要改成这样呢,因为我们要做一个计算器,所有的按键逻辑和显示工作由Java代码完成,而计算工作由C++ 代码去做,Java层要传递一个字符串给C++层,然后C++层把计算结果返回给Java层,Java层来显示计算结果。所以要加一个 String类型的形参,把返回值改成double。这时会报错,然后按 Alt+回车 键AS会自动修改。现在来到 native-lib.cpp文件,把刚开始AS生产的函数删掉,只保留这一个函数 JNIEXPORT jdouble JNICALL Java_com_bruce_counter_MainActivity_stringFromC(JNIEnv *env, jobject instance, jstring s_) { const char *s = env->GetStringUTFChars(s_, 0); // TODO // env->ReleaseStringUTFChars(s_, s); } NIEXPORT jdouble JNICALL 是在 jni.h中定义的返回值类型,不清楚jni类型的可以看一下 如果有env->ReleaseStringUTFChars(s_, s);代码,把他删掉,用不到。 完成的native-lib.cpp代码 #include <jni.h> #include <string> #include "Counter.h" using std::string; extern "C" JNIEXPORT jdouble JNICALL Java_com_bruce_counter_MainActivity_stringFromC(JNIEnv *env, jobject instance, jstring s_) { const char *s = env->GetStringUTFChars(s_, 0); // TODO // env->ReleaseStringUTFChars(s_, s); string str=s; delete s; Counter *c=new Counter(); double d=c->coutn(str); delete c; return d; } 指针 ‘s’ 指向的就是我们从Java层传过来的字符串,我们把他保存下来,然后delete s,听说不delete会内存泄露,还没求证,就先这样写吧。Counter类是负责计算的,调用Counter的countn函数,就能得到结果。 为啥要在native-lib.cpp中调用这些方法呢?我的理解native-lib相当于main函数,Java调用C++会先调用这个。好了,整个C++层代码基本完成了。 到Java中去调用吧。 displayStr=displayStr.replace("×","*").replace("÷","/"); screen.setText(stringFromC(displayStr)+"");//计算结束更新屏幕 先说一个遇到的坑,在Java中乘号用的'×',除号用的'÷',Java用的unicode编码,没有问题,但是C++默认用的是ASCII编码,不能使用’ב和’÷‘,我们使用‘*’和‘/’代替,所以在传入字符串时要替换一下displayStr=displayStr.replace("×","*").replace("÷","/"); 到这基本就好了,可以运行一下看看了。 发现写博客比写代码累多了,就先写到这吧,我已经把完整的demo上传到码云,需要的同学可以去下载。如果还有什么问题就贴在在评论区吧,一起学习。

优秀的个人博客,低调大师

《Android App开发入门:使用Android Studio 2.X开发环境》——第 3章 Android App界面设计 3-1 ...

第 3章 Android App界面设计 3-1 View与 ViewGroup(Layout):组件与布局 3-2 使用 LinearLayout建立界面布局 3-3 使用 weight属性控制组件的宽 /高 3-4 通过属性美化外观 3-5 用程序设置组件的外观属性 3-6 使用 ConstraintLayout 提升设计与执行的性能 3-7 使用 Gmail 将程序寄 3-1 View 与 ViewGroup(Layout):组件与布局

优秀的个人博客,低调大师

Python爬虫从入门到放弃(二十三)之 Scrapy的中间件Downloader Middleware实现User-Agent随机切换

总架构理解Middleware 通过scrapy官网最新的架构图来理解: 这个图较之前的图顺序更加清晰,从图中我们可以看出,在spiders和ENGINE提及ENGINE和DOWNLOADER之间都可以设置中间件,两者是双向的,并且是可以设置多层. 关于Downloader Middleware我在http://www.cnblogs.com/zhaof/p/7198407.html 这篇博客中已经写了详细的使用介绍。 如何实现随机更换User-Agent 这里要做的是通过自己在Downlaoder Middleware中定义一个类来实现随机更换User-Agent,但是我们需要知道的是scrapy其实本身提供了一个user-agent这个我们在源码中可以看到如下图: from scrapy import signals class UserAgentMiddleware(object): """This middleware allows spiders to override the user_agent""" def __init__(self, user_agent='Scrapy'): self.user_agent = user_agent @classmethod def from_crawler(cls, crawler): o = cls(crawler.settings['USER_AGENT']) crawler.signals.connect(o.spider_opened, signal=signals.spider_opened) return o def spider_opened(self, spider): self.user_agent = getattr(spider, 'user_agent', self.user_agent) def process_request(self, request, spider): if self.user_agent: request.headers.setdefault(b'User-Agent', self.user_agent) 从源代码中可以知道,默认scrapy的user_agent=‘Scrapy’,并且这里在这个类里有一个类方法from_crawler会从settings里获取USER_AGENT这个配置,如果settings配置文件中没有配置,则会采用默认的Scrapy,process_request方法会在请求头中设置User-Agent. 关于随机切换User-Agent的库 github地址为:https://github.com/hellysmile/fake-useragent安装:pip install fake-useragent 基本的使用例子: from fake_useragent import UserAgent ua = UserAgent() print(ua.ie) print(ua.chrome) print(ua.Firefox) print(ua.random) print(ua.random) print(ua.random) 这里可以获取我们想要的常用的User-Agent,并且这里提供了一个random方法可以直接随机获取,上述代码的结果为: 关于配置和代码 这里我找了一个之前写好的爬虫,然后实现随机更换User-Agent,在settings配置文件如下: DOWNLOADER_MIDDLEWARES = { 'jobboleSpider.middlewares.RandomUserAgentMiddleware': 543, 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, } RANDOM_UA_TYPE= 'random' 这里我们要将系统的UserAgent中间件设置为None,这样就不会启用,否则默认系统的这个中间会被启用定义RANDOM_UA_TYPE这个是设置一个默认的值,如果这里不设置我们会在代码中进行设置,在middleares.py中添加如下代码: class RandomUserAgentMiddleware(object): ''' 随机更换User-Agent ''' def __init__(self,crawler): super(RandomUserAgentMiddleware, self).__init__() self.ua = UserAgent() self.ua_type = crawler.settings.get('RANDOM_UA_TYPE','random') @classmethod def from_crawler(cls,crawler): return cls(crawler) def process_request(self,request,spider): def get_ua(): return getattr(self.ua,self.ua_type) request.headers.setdefault('User-Agent',get_ua()) 上述代码的一个简单分析描述:1. 通过crawler.settings.get来获取配置文件中的配置,如果没有配置则默认是random,如果配置了ie或者chrome等就会获取到相应的配置2. 在process_request方法中我们嵌套了一个get_ua方法,get_ua其实就是为了执行ua.ua_type,但是这里无法使用self.ua.self.us_type,所以利用了getattr方法来直接获取,最后通过request.heasers.setdefault来设置User-Agent 通过上面的配置我们就实现了每次请求随机更换User-Agent 所有的努力都值得期许,每一份梦想都应该灌溉!

优秀的个人博客,低调大师

23、 Python快速开发分布式搜索引擎Scrapy精讲—craw母版l创建自动爬虫文件—以及 scrapy item loader机制

转: http://www.bdyss.cn http://www.swpan.cn 用命令创建自动爬虫文件 创建爬虫文件是根据scrapy的母版来创建爬虫文件的 scrapy genspider -l查看scrapy创建爬虫文件可用的母版 Available templates:母版说明 basic 创建基础爬虫文件 crawl 创建自动爬虫文件 csvfeed 创建爬取csv数据爬虫文件 xmlfeed 创建爬取xml数据爬虫文件 创建一个基础母版爬虫,其他同理 scrapy genspider -t 母版名称 爬虫文件名称 要爬取的域名创建一个基础母版爬虫,其他同理如:scrapy genspider -tcrawllagou www.lagou.com 第一步,配置items.py接收数据字段 default_output_processor = TakeFirst()默认利用ItemLoader类,加载items容器类填充数据,是列表类型,可以通过TakeFirst()方法,获取到列表里的内容 input_processor = MapCompose(预处理函数)设置数据字段的预处理函数,可以是多个函数 #-*-coding:utf-8-*- #Defineherethemodelsforyourscrapeditems # #Seedocumentationin: #http://doc.scrapy.org/en/latest/topics/items.html #items.py,文件是专门用于,接收爬虫获取到的数据信息的,就相当于是容器文件 importscrapy fromscrapy.loader.processorsimportMapCompose,TakeFirst fromscrapy.loaderimportItemLoader#导入ItemLoader类也就加载items容器类填充数据 classLagouItemLoader(ItemLoader):#自定义Loader继承ItemLoader类,在爬虫页面调用这个类填充数据到Item类 default_output_processor=TakeFirst()#默认利用ItemLoader类,加载items容器类填充数据,是列表类型,可以通过TakeFirst()方法,获取到列表里的内容 deftianjia(value):#自定义数据预处理函数 return'叫卖录音网'+value#将处理后的数据返给Item classLagouItem(scrapy.Item):#设置爬虫获取到的信息容器类 title=scrapy.Field(#接收爬虫获取到的title信息 input_processor=MapCompose(tianjia),#将数据预处理函数名称传入MapCompose方法里处理,数据预处理函数的形式参数value会自动接收字段title ) 第二步,编写自动爬虫与利用ItemLoader类加载items容器类填充数据 自动爬虫Rule()设置爬虫规则 参数: LinkExtractor()设置url规则 callback='回调函数名称' follow=True 表示在抓取页面继续深入 LinkExtractor()对爬虫获取到的url做规则判断处理 参数: allow= r'jobs/' 是一个正则表达式,表示符合这个url格式的,才提取 deny= r'jobs/' 是一个正则表达式,表示符合这个url格式的,不提取抛弃掉,与allow相反 allow_domains= www.lagou.com/ 表示这个域名下的连接才提取 deny_domains= www.lagou.com/ 表示这个域名下的连接不提取抛弃 restrict_xpaths= xpath表达式 表示可以用xpath表达式限定爬虫只提取一个页面指定区域的URL restrict_css= css选择器,表示可以用css选择器限定爬虫只提取一个页面指定区域的URL tags= 'a' 表示爬虫通过a标签去寻找url,默认已经设置,默认即可 attrs= 'href' 表示获取到a标签的href属性,默认已经设置,默认即可 * 利用自定义Loader类继承ItemLoader类,加载items容器类填充数据 *ItemLoader()实例化一个ItemLoader对象来加载items容器类,填充数据,如果是自定义Loader继承的ItemLoader同样的用法 参数: 第一个参数:要填充数据的items容器类注意加上括号, 第二个参数:response* ItemLoader对象下的方法: add_xpath('字段名称','xpath表达式')方法,用xpath表达式获取数据填充到指定字段 add_css('字段名称','css选择器')方法,用css选择器获取数据填充到指定字段 add_value('字段名称',字符串内容)方法,将指定字符串数据填充到指定字段 load_item()方法无参,将所有数据生成,load_item()方法被yield后数据被填充items容器指定类的各个字段 爬虫文件 #-*-coding:utf-8-*- importscrapy fromscrapy.linkextractorsimportLinkExtractor fromscrapy.spidersimportCrawlSpider,Rule fromadc.itemsimportLagouItem,LagouItemLoader#导入items容器类,和ItemLoader类 classLagouSpider(CrawlSpider):#创建爬虫类 name='lagou'#爬虫名称 allowed_domains=['www.luyin.org']#起始域名 start_urls=['http://www.luyin.org/']#起始url rules=( #配置抓取列表页规则 Rule(LinkExtractor(allow=('ggwa/.*')),follow=True), #配置抓取内容页规则 Rule(LinkExtractor(allow=('post/\d+.html.*')),callback='parse_job',follow=True), ) defparse_job(self,response):#回调函数,注意:因为CrawlS模板的源码创建了parse回调函数,所以切记我们不能创建parse名称的函数 #利用ItemLoader类,加载items容器类填充数据 item_loader=LagouItemLoader(LagouItem(),response=response) item_loader.add_xpath('title','/html/head/title/text()') article_item=item_loader.load_item() yieldarticle_item items.py文件与爬虫文件的原理图 【转载自:http://www.lqkweb.com】

优秀的个人博客,低调大师

阿里云大学「学习路线」,一站式从入门到高手——Python、Java、前端、运维、数据库、云原生……

阿里云大学有哪些学习路线? 已上线(免费学习+自测考试): Python学习路线:https://edu.aliyun.com/roadmap/pythonJava学习路线:https://edu.aliyun.com/roadmap/java前端开发学习路线:https://edu.aliyun.com/roadmap/frontendLinux运维学习路线:https://edu.aliyun.com/roadmap/linux数据库学习路线:https://edu.aliyun.com/roadmap/databaseCNCF × Alibaba云原生技术公开课:https://edu.aliyun.com/roadmap/cloudnative 即将上线: 迁移上云、大数据技术、人工智能、微服务、IoT、小程序……,敬请关注阿里云

优秀的个人博客,低调大师

Python爬虫入门教程 41-100 Fiddler+夜神模拟器+雷电模拟器配置手机APP爬虫部分

爬前叨叨 从40篇博客开始,我将逐步讲解一下手机APP的爬虫,关于这部分,我们尽量简化博客内容,在这部分中可能涉及到一些逆向,破解的内容,这部分尽量跳过,毕竟它涉及的东西有点复杂,并且偏离了爬虫体系太远,有兴趣的博友,可以一起研究下。 之前看到知乎有人对手机App爬虫归类,基本符合规则,接下来的10篇博客可能集中在80%的App上,所以还是比较简单的 50%的app,通过抓包软件就可以分析出抓取参数并抓取到信息。 30%的app,可能需要适当的反编译,分析出加密算法并抓取到信息。 10%的app,可能加固,需要脱壳,然后反编译,分析出加密算法并抓取到信息 10%的app,通过各式各样的签名,证书,设备绑定等方法,隐藏加密算法。 首先配置第一轮的环境,配置好了,下一篇博客,就采用Fiddler+夜神模拟器[雷电模拟器]等实现儿歌多多APP的数据抓

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册