2020-2-9 387 0
哔哔大数据

搭建前的准备搭建Scala环境首先需要你的IDEA需要搭建好Scala的环境(可以参考这篇)还需要一个和Hadoop的Windows版二进制文件下载地址:http://public-repo-1.hortonworks.com/hdp-win-alpha/winutils.exe搭建配置winutils创建一个目录E:\winutils\bin把winutils.exe放进去配置环境变量//新建变量变量名:HADOOP_HOME变量值:E:\winutils//把新建变量加入Path%HADOOP%\bin这样就安装好了配置IDEA在IDEA配置好Scala后,就只需要在pom.xml文件里添加Spark依赖就好pom.xml文件<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.bigdataboy</groupId><artifactId>SparkDemo</artifactId><version>1.0</version><dependencies><!--Spark依赖--><!--https://mvnrepository.com/artifact/org.apache.spark/spark-core--><dependency><groupId>org.apache.spark</groupId><artifactId>spark-core_2.11</artifactId><version>2.0.0</version></dependency></dependencies></project>等待依赖下载完成Spark案例第一个Spark案例,单词统计统计数据helloScalahelloJavahelloPython统计代码defmain(args:Array[String]):Unit={//设定Spark运行环境valconf:SparkConf=newSparkConf().setMaster("local[*]").setAppName("wc")//创建Spark上下文连接对象valsc=newSparkContext(conf)//读取文件,一行数据为一个元素vallines:RDD[String]=sc.textFile("./src/main/Scala/data.txt")//空格分隔,使其扁平化valwords:RDD[String]=lines.flatMap(_.split(""))//格式化数据,方便统计valwordToOne:RDD[(String,Int)]=words.map((_,1))//聚合valwordToSum:RDD[(String,Int)]=wordToOne.reduceByKey(_+_)//收集并打印结果println(wordToSum.collect().mkString(","))//保存结果wordToSum.saveAsTextFile("./src/main/Scala/out")}

哔哔大数据

案例说明使用Flume监控一个本地目录,如果目录有新的文件产生,则会自动传到HDFS上配置本案例任务需要的Flume文件在Flume的conf/目录下创建,名称为spooldir-hdfs.properties#相当定义Flume的三个组件变量名agent1.sources=source1agent1.sinks=sink1agent1.channels=channel1#配置source组件agent1.sources.source1.type=spooldir#监控的本地路径agent1.sources.source1.spoolDir=/home/logs/agent1.sources.source1.fileHeader=false#配置拦截器agent1.sources.source1.interceptors=i1agent1.sources.source1.interceptors.i1.type=hostagent1.sources.source1.interceptors.i1.hostHeader=hostname#配置sink组件agent1.sinks.sink1.type=hdfsagent1.sinks.sink1.hdfs.path=hdfs://192.168.176.65:9000/locadir/flume_log/%y-%m-%d/%H-%Magent1.sinks.sink1.hdfs.filePrefix=eventsagent1.sinks.sink1.hdfs.maxOpenFiles=5000agent1.sinks.sink1.hdfs.batchSize=100agent1.sinks.sink1.hdfs.fileType=DataStreamagent1.sinks.sink1.hdfs.writeFormat=Textagent1.sinks.sink1.hdfs.rollSize=102400agent1.sinks.sink1.hdfs.rollCount=1000000agent1.sinks.sink1.hdfs.rollInterval=60#agent1.sinks.sink1.hdfs.round=true#agent1.sinks.sink1.hdfs.roundValue=10#agent1.sinks.sink1.hdfs.roundUnit=minuteagent1.sinks.sink1.hdfs.useLocalTimeStamp=true#Useachannelwhichbufferseventsinmemoryagent1.channels.channel1.type=memoryagent1.channels.channel1.keep-alive=120agent1.channels.channel1.capacity=500000agent1.channels.channel1.transactionCapacity=600#Bindthesourceandsinktothechannelagent1.sources.source1.channels=channel1agent1.sinks.sink1.channel=channel1任务命令说明下面命令是在FLume的根目录里执行的flume-ngagent-cconf-fconf/spooldir-hdfs.properties-nagent1-Dflume.root.logger=INFO,console参数作用实例conf或-c指定配置文件的地址,包含flume-env.sh和log4j的配置文件-cconf-conf-file或-f当前任务的配置文件地址-fconf-fileconf/spooldir-hdfs.properties-name或-nagent名称-nameagent1-zzookeeper连接的字符串-zzkhost:2181,zkhost1:2181-pzookeeper中的存储路径前缀-p/flume-Dflume启动日志打印到当前控制台-Dflume.root.logger=INFO,console测试任务开启两个窗口,其中一个进入监控的目录,查看HDFS上的目录另一个窗口运行命令,这样就运行成功在/home/logs目录下创建一个文件,就会发现该文件被自动上传到了HDFS上

Python极客

说明上一个案例,对自带的ImagePipeline写了一个图片下载案例,现在对最后的小结进行改进对图片进行进行自定义名称存储主要涉及ImagePipeline类的继承与方法的重写优化开始优化Wallpaperspider.py文件defparse(self,response):#循环li标签forurltaginresponse.xpath('//ul[@class="clearfix"]/li/a'):#获取图片标题titles=urltag.xpath('./img/@alt').get()#获取图片链接url=urltag.xpath('./img/@src').get()#-->没有http://的链接urls_pic=response.urljoin(url)#拼接URL#传给数据ItemyieldImagesappItem(titles=titles,image_urls=urls_pic)优化pipeline.py文件继承ImagePipeline类导入ImagesPipeline类fromscrapy.pipelines.imagesimportImagesPipeline继承ImagesPipeline类classPicImagesPipeline(ImagesPipeline):pass重写get_media_requests()方法此方法是构造请求的Ruquest对象#构造下载,首先调用的函数defget_media_requests(self,item,info):#导入Request模块fromscrapy.http.requestimportRequest#在item中取出url,再把item给meta参数进行传递#在后面方法中,可以从request对象的meta属性获得item的数据yieldRequest(url=item['image_urls'],meta={'item':item})重写file_path()方法此方法是返回存储的路径deffile_path(self,request,response=None,info=None):#从request对象的meta属性获取titletitle=request.meta['item']['titles']#构造存储路径path=title+'.jpg'returnpath修改settings.py文件因为使用了自定义的Pipeline,所以我们需要指定我们重写的Pipeline#Configureitempipelines#Seehttps://docs.scrapy.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES={'ImagesApp.pipelines.PicImagesPipeline':1,#继承的重写ImagesPipeline类}运行爬虫scrapycrawlWallPaperSpider

Python极客

使用官方提供的PiplineScrapy框架为下载的item中包含的图片提供了一个可以重用的图片下载pipeline。这些pipeline有共同的方法和结构。一般会使用到有FilesPipeline、ImagesPipline。使用官方Pipline的好处避免重新下载最近已经下载的数据方便指定下载的路径方便的转换图片的格式方便生成略缩图方便检测图片的宽高,确保满足最小值异步下载,效率非常高ImagesPipline的使用准备使用ImagesPipline,需要提前下载好Pillow图片处理库当使用ImagesPipline下载图片的时候,按照以下步骤完成1.定义Item属性必须要定义两个个默认的item属性:image_urls:存储下载图片的链,需要传递一个列表。images:文件下载完成后,会把图片的相关信息存储到这个属性里,比如下载的路径、下载的URL、文件的校验码…classMaybachItem(scrapy.Item):image_urls=scrapy.Field()images=scrapy.Field()2.启用ImagesPipline管道在settings.py里开启#Configureitempipelines#Seehttps://docs.scrapy.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES={#'Maybach.pipelines.MaybachPipeline':300,#开启图片下载器'scrapy.pipelines.images.ImagesPipeline':1,}3.配置ImagesPipline下载路径在settings.py里添加上#ImagesPipline下载路径,可以使用OS模块来指定路径#没有这个路径,会自动创建IMAGES_STORE='路径'0x00创建爬虫工程scrapystartprojectImagesApp(创建Scrapy工程)cdImagesApp(进入工程目录)scrapygenspiderWallPaperSpiderpic.netbian.com(创建爬虫)0x01配置爬虫关闭机器人协议#Obeyrobots.txtrulesROBOTSTXT_OBEY=False设置请求头#Crawlresponsiblybyidentifyingyourself(andyourwebsite)ontheuser-agentUSER_AGENT='Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/76.0.3809.100Safari/537.36'开启ImagesPipline管道#Configureitempipelines#Seehttps://docs.scrapy.org/en/latest/topics/item-pipeline.htmlITEM_PIPELINES={#'ImagesApp.pipelines.ImagesappPipeline':300,(注释掉)'scrapy.pipelines.images.ImagesPipeline':1,}配置图片的下载路径importosIMAGES_STORE=os.path.join(os.path.dirname(os.path.dirname(__file__)),'img')设置Item属性在items.py里classImagesappItem(scrapy.Item):#definethefieldsforyouritemherelike:#name=scrapy.Field()image_urls=scrapy.Field()images=scrapy.Field()0x02编写爬虫程序通过对网页的分析,我们需要的链接在这些li标签下获取图片链接但这些url,没有协议头defparse(self,response):url=response.xpath('//ul[@class="clearfix"]/li/a/img/@src').getall()print(url)添加协议头response.urljoin(url)方法会自动把相应的协议头加上urls_pic=list(map(lambdaurl:response.urljoin(url),urls))把图片链接通过Item传给ImagesPipeline下载导入ImagesappItem,传入url列表,启动爬虫fromImagesApp.itemsimportImagesappItemdefparse(self,response):urls=response.xpath('//ul[@class="clearfix"]/li/a/img/@src').getall()urls_pic=list(map(lambdaurl:response.urljoin(url),urls))yieldImagesappItem(image_urls=urls_pic)#启动爬虫scrapycrawlWallPaperSpider0x03小结这个小案例是直接使用的官方的ImagePipeline下载,所以没有对图片进行重命名,或者分类等操作,需要实现这些操作,就需要继承ImagesPipeline类,然后重新里面的相关方法,可以查看改进版。

编程杂谈

案例效果涉及的重要知识当前标签的索引获取index()HTML代码<divclass="wrapper"><ulid="left"><li><ahref="#">女靴</a></li><li><ahref="#">雪地靴</a></li><li><ahref="#">冬裙</a></li><li><ahref="#">呢大衣</a></li><li><ahref="#">毛衣</a></li><li><ahref="#">棉服</a></li><li><ahref="#">女裤</a></li><li><ahref="#">羽绒服</a></li><li><ahref="#">牛仔裤</a></li></ul><ulid="center"><li><ahref="#"><imgsrc="img/女靴.jpg"/></a></li><li><ahref="#"><imgsrc="img/雪地靴.jpg"/></a></li><li><ahref="#"><imgsrc="img/冬裙.jpg"/></a></li><li><ahref="#"><imgsrc="img/呢大衣.jpg"/></a></li><li><ahref="#"><imgsrc="img/毛衣.jpg"/></a></li><li><ahref="#"><imgsrc="img/棉服.jpg"/></a></li><li><ahref="#"><imgsrc="img/女裤.jpg"></a></li><li><ahref="#"><imgsrc="img/羽绒服.jpg"/></a></li><li><ahref="#"><imgsrc="img/牛仔裤.jpg"/></a></li><li><ahref="#"><imgsrc="img/女包.jpg"/></a></li><li><ahref="#"><imgsrc="img/男包.jpg"/></a></li><li><ahref="#"><imgsrc="img/登山鞋.jpg"/></a></li><li><ahref="#"><imgsrc="img/皮带.jpg"/></a></li><li><ahref="#"><imgsrc="img/围巾.jpg"/></a></li><li><ahref="#"><imgsrc="img/皮衣.jpg"/></a></li><li><ahref="#"><imgsrc="img/男毛衣.jpg"/></a></li><li><ahref="#"><imgsrc="img/男棉服.jpg"/></a></li><li><ahref="#"><imgsrc="img/男靴.jpg"/></a></li></ul><ulid="right"><li><ahref="#">女包</a></li><li><ahref="#">男包</a></li><li><ahref="#">登山鞋</a></li><li><ahref="#">皮带</a></li><li><ahref="#">围巾</a></li><li><ahref="#">皮衣</a></li><li><ahref="#">男毛衣</a></li><li><ahref="#">男棉服</a></li><li><ahref="#">男靴</a></li></ul></div>CSS代码*{margin:0;padding:0;font-size:12px;}ul{list-style:none;}a{text-decoration:none;}.wrapper{width:298px;height:248px;margin:100pxauto0;border:1pxsolidpink;overflow:hidden;}#left,#center,#right{float:left;}#leftli,#rightli{background:url(../img/lili.jpg)repeat-x;}#leftlia,#rightlia{display:block;width:48px;height:27px;border-bottom:1pxsolidpink;line-height:27px;text-align:center;color:black;}#leftlia:hover,#rightlia:hover{color:#fff;background-image:url(../img/abg.gif);}#center{border-left:1pxsolidpink;border-right:1pxsolidpink;}img{width:200px;height:250px;}JS代码$(function(){//绑定左边的li标签鼠标属性$('#leftli').mouseover(function(){//获取当前li标签索引varindex=$(this).index();//展示相应索引图片$('#centerli').eq(index).show();//隐藏其他图片$('#centerli').eq(index).siblings('li').hide()//链式写法$('#centerli').eq(index).show().siblings('li').hide();});//绑定右边的li标签鼠标属性$('#rightli').mouseover(function(){//获取鼠标当前索引9是左边的图片是9开始的varindex=$(this).index()+9;//展示相应索引图片$('#centerli').eq(index).show();//隐藏其他索引图片$('#centerli').eq(index).siblings('li').hide()//链式写法$('#centerli').eq(index).show().siblings('li').hide();})})案例图片下载:淘宝服饰案例

编程杂谈

效果CSS代码*{padding:0;margin:0;}ul{list-style-type:none;margin:100px;}.menu-head{width:185px;height:47px;line-height:47px;padding-left:38px;font-size:17px;color:#475052;cursor:pointer;border:1pxsolid#e1e1e1;position:relative;margin:0px;font-weight:bold;background:#f1f1f1centerrightno-repeat;}.menu-list.current{background:#f1f1f1centerrightno-repeat;}.menu-body{width:223px;height:auto;overflow:hidden;line-height:38px;border-left:1pxsolid#e1e1e1;backguound:#fff;border-right:1pxsolid#e1e1e1;display:none;}.menu-bodya{display:block;width:223px;height:38px;line-height:38px;padding-left:38px;color:#777;background:#fff;text-decoration:none;border-bottom:1pxsolid#e1e1e1;}HTML代码<body><ulclass="menu-list"><li><pclass="menu-head">目标管理</p><divclass="menu-body"><ahref="#">主题空间</a><ahref="#">项目任务</a><ahref="#">工作计划</a><ahref="#">日程事件</a><ahref="#">时间视图</a></div></li><li><pclass="menu-head">会议管理</p><divclass="menu-body"><ahref="#">主题空间</a><ahref="#">会议安排</a><ahref="#">待开会议</a><ahref="#">已开会议</a><ahref="#">会议资源</a></div></li><li><pclass="menu-head">知识社区</p><divclass="menu-body"><ahref="#">我的收藏</a><ahref="#">知识广场</a><ahref="#">文档中心</a><ahref="#">我的博客</a><ahref="#">文档库管理</a></div></li></ul></body>JS代码第一代$(function(){//鼠标经过$('.menu-head').mouseover(function(){//$(this)JQuery当前元素//查找当前元素的,同级元素$(this).siblings('.menu-body').show()})//鼠标离开$('.menu-head').mouseout(function(){//$(this)JQuery当前元素$(this).siblings('.menu-body').hide()})})JS代码第二代利用hover()函数,合并鼠标的经过与离开的事件hover([over,]out)参数:over:鼠标移到元素上要触发的函数out:鼠标移出元素要触发的函数//组合写法$('.menu-head').hover(//鼠标经过function(){$(this).siblings('.menu-body').slideDown()},//鼠标离开function(){$(this).siblings('.menu-body').slideUp()});JS代码第三代利用hover()函数,合并鼠标的经过与离开的事件hover([over,]out)只写一个参数,代表无论鼠标经过还是鼠标退出,都要执行这个函数//组合写法$('.menu-head').hover(//鼠标事件,切换滑动function(){$(this).siblings('.menu-body').slideToggle()})

编程杂谈

项目背景我们可以通过爬虫来模拟登录来查询自己的成绩,这其中最重要的就是登录这个关卡,只要通过了,就可以方便的查询自己的成绩了。但是我们还是要在法律的允许条件下爬取数据,下列的代码已进行隐私处理,并不针对任何组织。爬虫分析通过抓包,发现登录需要提交学号、密码、验证码、VIEWSTATE通过分析发现其中的VIEWSTATE参数就在网页中,所以我们可以通过正则表达式匹配出来爬虫项目结构importreimportrequestsclassAPI(object):...classTool(object):...API类·通过抓包,知道了以下接口classAPI(object):#登录页GET_INDEX="http://XXXXXXXX:XXXX/"#获取验证码GET_YZM_URL='http://XXXXXXXX:XXXX/CheckCode.aspx'#登录POST_LOGIN='http://XXXXXXXX:XXXX/default2.aspx'Tool类classTool(object):session=requests.session()VIEWSTATE=""#获取VIEWSTATE参数@classmethoddefgetHtml(cls):response=cls.session.get(API.GET_INDEX).textcls.VIEWSTATE=re.search(r'__VIEWSTATE"value="(.*?)"/>',response).group(1)#下载验证码在当前路径@classmethoddefdownload_yzm(cls):yzm_image=cls.session.get(url=API.GET_YZM_URL)withopen("yzm.jpg",'wb')asfile:file.write(yzm_image.content)#登录方法@classmethoddeflogin(cls,account,pwd,yzm):data={"__VIEWSTATE":cls.VIEWSTATE,"TextBox1":account,"TextBox2":pwd,"TextBox3":yzm,"RadioButtonList1":"%D1%A7%C9%FA","Button1":"",}response=cls.session.post(url=API.POST_LOGIN,data=data)response.encoding=response.apparent_encodingresponse=response.texttry:message=re.search(r">alert\('(.*?)'\);</script>",response).group(1)except:#登录成功跳转到详情页xm=re.search(r'<spanid="xhxm">(.*?)同学</span>',response).group(1)print("欢迎"+xm+"登录成功")else:#打印出登录失败信息print(message)主函数defmain():t=Tool()#实例化类t.getHtml()#获取VIEWSTATEt.download_yzm()#下载验证码account=input("请输入你的学号:")pwd=input("请输入你的密码:")yzm=input("请输入验证码:")t.login(account,pwd,yzm)#运行登录方法

哔哔大数据

需要导入的包注意导入mapreduce的新版本包带mapreduce的importorg.apache.hadoop.conf.Configuration;importorg.apache.hadoop.fs.Path;importorg.apache.hadoop.io.LongWritable;importorg.apache.hadoop.io.Text;importorg.apache.hadoop.mapreduce.Job;importorg.apache.hadoop.mapreduce.Mapper;importorg.apache.hadoop.mapreduce.Reducer;importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;importorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;importjava.io.IOException;MapReduce程序结构publicclassWordCountApp{//进行分割的map类publicstaticclassMyMapperextendsMapper<LongWritable,Text,Text,LongWritable>{......}//归并操作的Reducer类publicstaticclassMyReducerextendsReducer<Text,LongWritable,Text,LongWritable>{......}//定义Drive类(main类)publicstaticvoidmain(String[]args)throwsException{......}}map类:对读取的每一行单词进行分割操作,形成键值对Reducer类:把分割完成的键值对-->key,value,进行归并求和并输出Drive类:设置MapReduce作业提交、数据的输入路径、map的处理类、Reducer的处理类、数据的输出路径map分割操作的详解Mapper类四个泛型参数前两个参数为map输入类型,后两个参数为map的输出类型LongWritable:输入数据的首行的偏移量(相当于Java的Long类型)Text:输入的每一行的数据(相当于Java的String类型)Text:分割之后产生的键值对键的类型LongWritable:分割之后产生的键值对值的类型publicstaticclassMyMapperextendsMapper<LongWritable,Text,Text,LongWritable>{/**reduce参数:*LongWritablekey:输入数据的行的偏移量*Textvalue:读取的每一行数据*Contextcontext上下文连接**/@Overrideprotectedvoidmap(LongWritablekey,Textvalue,Contextcontext)throwsIOException,InterruptedException{//接收到的每一行数据,转化成Java的字符串Stringline=value.toString();//把字符串进行空格分隔,返回一个数组String[]words=line.split("");//返回字符串数组//利用循环使用context.write(key,value);组合成k,v形式for(Stringword:words){//通过context(上下文连接)把map分割的k、v输出context.write(newText(word),newLongWritable(1));//前面设置了返回值为Text,LongWritable类型}}}Reducer归并操作的详解Reducer类四个泛型参数前两个参数为Reducer输入类型,后两个参数为Reducer的输出类型Text:map的输出类型,就是Reduse的输入类型LongWritable:map的输出类型,就是Reduse的输入类型Text:进行归并操作之后的键值对-->键的类型LongWritable:进行归并操作之后的键值对-->的值类型publicstaticclassMyReducerextendsReducer<Text,LongWritable,Text,LongWritable>{/**reduce参数:*Textkey:Map操作后的键值对的键*Iterable<LongWritable>values:当进行Map操作之后,一个键可能有很多对应的值所以是一个迭代类型*Contextcontext上下文连接**/@Overrideprotectedvoidreduce(Textkey,Iterable<LongWritable>values,Contextcontext)throwsIOException,InterruptedException{//这里只需要把出现的迭代类型进行求和longsum=0;for(LongWritablevalue:values){//把LongWritable转成Java的数据类型进行求和sum+=value.get();}//最终的统计结果通过上下文连接输出context.write(key,newLongWritable(sum));}}定义Drive类(main类)publicstaticvoidmain(String[]args)throwsException{//抛出异常//创建一个Configuration对象Configurationconfiguration=newConfiguration();//注意是hadoop里的//创建一个Job,如有异常,先把异常抛出Jobjob=Job.getInstance(configuration,"wordCount");//设置Job的处理类job.setJarByClass(WordCountApp.class);//类名称//设置需要处理数据的输入路径FileInputFormat.setInputPaths(job,newPath(args[0]));//路径通过脚本参数传入//设置map的处理主类job.setMapperClass(MyMapper.class);//指定Mapper处理类job.setMapOutputKeyClass(Text.class);//设置map处理类的k输出类型job.setMapOutputValueClass(LongWritable.class);//设置map处理类的v输出类型//设置reducer的处理主类job.setReducerClass(MyReducer.class);//指定Reduse处理类job.setOutputKeyClass(Text.class);//设置reducer处理类的k输出类型job.setOutputValueClass(LongWritable.class);//设置reducer处理类的v输出类型//设置作业的输出路径FileOutputFormat.setOutputPath(job,newPath(args[1]));//路径通过脚本参数传入//提交作业booleanb=job.waitForCompletion(true);//参数为true确定提交//退出程序System.exit(b?0:1);//程序推出的状态码0正常}上传到hadoop执行首先把程序打成jar包。idea打jar教程hadoop执行jar命令:hadoopjarJar名称输入路径输出路径hadoopjarhadooptrain.jarhdfs://192.168.5.137:9000/words.txthdfs://192.168.5.137:9000/output执行结果