精华内容
下载资源
问答
  • 手机爬虫
    更多相关内容
  • 热销手机——Python爬虫数据分析 [环境] 视窗 蟒蛇3.8 [scrapy-spider] scrapy项目1:taobaoSpider scrapy项目2:jdSpider [数据资源] 来源:csv文件存储 [数据分析] 任务*.py [样本] 效果展示:task*.png
  • 快速入门手机爬虫

    千次阅读 2020-11-08 11:04:51
    快速入门手机爬虫 前言: 本人是在接触python爬虫后,萌发了“Android开发应该也能实现爬虫效果,这样用手机爬是不是会更方便”这一念想。于是兴趣使然就开始了手机爬虫的探索之旅。虽然这路已被探索无数次,但是...

    前言:
    本人是在接触python爬虫后,萌发了“Android开发应该也能实现爬虫效果,这样用手机爬是不是会更方便”这一念想。于是兴趣使然就开始了手机爬虫的探索之旅。虽然这路已被探索无数次,但是对于未曾去过的我依旧向往。

    一、整装待发:

    1)爬虫工具和环境:

    1. Android系统
    2. Android studio

    2)入手前准备:

    1. 了解kotlin语言:由于Android studio 4.1使用的是kotlin语言,所以需要自行稍微了解一下其语言特性,如定义方式、逻辑表达式,当然你会发现kotlin语言还是比较友好的。
    2. 了解线程和多线程
    3. 了解爬虫流程
    4. 了解数据长久化

    二、地图浏览:

    要实现如何手机爬虫,首先要知道爬虫的流程:
    1)明确爬取目标
    2)伪装访问
    3)获取网页源码
    4)提取出需要内容(常用手法:洗刷数据)
    5)检验提取内容
    6)爬取内容
    7)爬取内容持久化

    三、景点分析

    <一>Jsoup使用

    访问网页的手法有很多,如get、HttpClient 、HttpURLConnection等,但是我还是比较倾向于Jsoup。除了好用外,更多的是它和python的requests比较相似,所以用起来也比较顺手。

    附上常用使用方法:

     var d:Document = Jsoup.connect("这里填写网页地址")
                            .userAgent("用户代理").get()
                    
    

    userAgent:获取方法参考https://jingyan.baidu.com/article/95c9d20d7bca17ec4e7561a4.html

    坑点
    (1)这个方法需要配合线程使用,不然会报错。
    (2)当地址是下载文件的地址时,可能会报org.jsoup.UnsupportedMimeTypeException: Unhandled content type Must be text/* ,处理手法是加入ignoreContentType函数

    Jsoup.connect(strvideoUrl)
                            .userAgent("用户代理")
                            .ignoreContentType(true).get()
    

    <二>常用伪装访问:

    1)Jsoup.connect(strvideoUrl).userAgent(…)
    2)Jsoup.connect(strvideoUrl).referrer(…)
    3)Jsoup.connect(strvideoUrl).cookie(…)
    注:括号内的…表示参数,因为懒所以就用…表示。用法类比python的request

    <三>提取出需要内容:

    利用Document类对象存储的内容进行提取。如何提取,可参考jsoup是如何选择指定元素的

    个人极不推荐使用正则来洗刷数据,因为在Android里,正则的匹配率实在是低得感人,不好用。
    推荐的手法是,先用Document的select和Elements的getElementsByAttribute函数进行筛选,在Document.select和Elements.getElementsByAttribute无法一步到位精准筛选到目标时,再考虑用Elements.attr()函数进行进一步筛选。

    elementUrl.first().getElementsByAttribute("src")//利用属性的名称来定位
    

    筛选数据常用到的:
    1)Document.select
    2)Elements.getElementsByAttribute
    3)Elements.attr
    4)Elements.removeAttr
    5)Elements.replace

    var elementTitle: Elements =d.select("[class*=\"video-title title-truncate m-t-5\"]")
    //d为Document对象,获取方法如:var d:Document=Jsoup.connect("http://www.baidu.com/").get()
    

    注:需要进行字符分割时,可以用String自带的split函数进行操作,比较便捷。

    d.text().toString().split("#EXT-X-DISCONTINUITY")
    

    <四>数据持久化

    所谓的数据持久化,无非就是把数据保存下来,这一步无论在Python爬虫还是今天讲的Android爬虫,都是属于核心部分。下载手法有以下几种:

     1. 自己封装URLConnection 连接请求类
     2. Android自定的下载管理
     3. 使用第三方 okhttp 网络请求框架
    

    具体说明参考:Android 文件下载三种基本方式

    其实这三种方式,我都试过,最后因为便捷,所以选择了第二个下载方案:Android自定的下载管理。因为这个下载方案是调用了现有的下载框架进行下载,减轻了许多代码量。

    优点: 会在notification 显示下载的进度,同时可以暂停、重新连接。

    使用手法:

       //创建下载任务,downloadUrl就是下载链接
        val request = DownloadManager.Request(Uri.parse(strvideodownloadUrl[i]))
        //指定下载路径和下载文件名
        request.setDestinationInExternalPublicDir("", "/storage/"+strTitle+'/')
        //获取下载管理器
        val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        //将下载任务加入下载队列,否则不会进行下载
        downloadManager.enqueue(request)
        println(i.toString()+".ts"+"已完成"+'\n')
    

    与Python对比:
    在Python中下载一般都是使用多线程调用函数下载,但是 “自定的下载管理” 这种下载方案使Android爬虫的下载方式具有一定的先天优势。

    Okey,到这里其实整个Android爬虫就讲完了,是不是觉得很简单呢。摸索的过程比较曲折,但是也比较有趣。最后给出本文的另一核心重点–视频合并。

    <五>视频合并

    网上爬下来的视频文件一般都是ts文件居多,当然Android是能播放ts文件的,但是一百或几百个ts,一个个播放这也是需要相当的耐心,那合并成一个mp4文件是不是众望所归?Python可以通过调用”copy /b“指令进行ts文件合并,那Android是如何把多个ts文件合并成一个文件呢?

    想必很多人在网上搜索过,但是多数搜索到的是使用软件进行合并,但是作为一个开发爱好者,还是想自己的软件能自实现合并。

    val fos = FileOutputStream(realFile)  //fos承载的是输出文件
     var file:File =File("/storage/emulated/0/storage/"+strTitle+'/'+"video"+strnum+".ts")
    
      if (file.exists()){
          var fis=FileInputStream(file)
          var tmpBytes = ByteArray(fis.available())
          var length = tmpBytes.size
          println(length)
          if(i==0){
              while(fis.read(tmpBytes)!=-1){
                  fos.write(tmpBytes,0,length)
              }
          }
          //之后的文件,去掉头文件就可以了.amr格式的文件的头信息为 6字节
          //当然去不去这6字节都是能合并的,合并出来的文件也能正常播放
          else{
              while(fis.read(tmpBytes)!=-1){
                  fos.write(tmpBytes,6,length-6)
              }
          }
          fos.flush()
          fis.close()
     }
    

    后感: 经过Android爬虫之旅后,感觉还是Python比较强大。

    到此,全文已完结。文笔不好,将就看看。如果本文能让你学到东西,希望能点个赞。

    成果展示:

    在这里插入图片描述
    点击”案例展示“按钮访问目标地址并开始下载
    在这里插入图片描述
    在这里插入图片描述
    下载完成后,点击下方”等待下载完毕后点击下载“(打错字,改成合并囧)按钮,然后就会合并ts文件,并删除ts文件
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 中关村手机爬虫

    2018-05-18 13:16:28
    爬取页面手机信息,并且通过mysql进行插入。方便查询!
  • 爬虫:京东手机图片爬取
  • 一段关于手机爬虫的代码,在运行时可以拿取到网页搜索结果的url,但是点击进去的时候显示404
  • 京东手机爬虫

    千次阅读 2017-10-20 14:15:24
    一只小小的京东手机爬虫~

    拖延症晚期的我终于于于于于于于又来更新博客了。国庆自己写了个京东手机的爬虫,爬取了京东商城所有手机的名称,价格,配置,属性等信息,算是实现了预期的功能。这里mark一下,以后遇到类似的项目都可以借鉴。

    这次的京东手机爬虫和以往的都不太相同,之前爬取的都是静态网页,所有需要的内容都可以在一个页面中找到,比较基础。这次的爬虫涉及到动态加载的网页,具体的话参加后面的详细说明。

    在开始具体的爬虫之前,我想先总结一下编写简单爬虫的思路。首先,秉承“万物皆可爬”的理念,我们能找到的URL都是可以爬取的(如果是某些大型的网站可能会有反爬措施,相应的会有特殊的手段进行爬取。当然,爬和反爬就像矛与盾的关系,身为菜鸟的我在爬京东时总是战战兢兢,生怕什么时候就把我的IP封了=.=)。带着这种舍我其谁的勇气,我们来试试吧~

    简单梳理一下之前做过的小爬虫,大概分为以下几个步骤:

    1.      俗话说,“巧妇难为无米之炊”,我们先要找到需要爬取的网页地址,这是我们一切工作的前提。(URL可能有多个哦)

    2.      对于URL,通过解析将其转换为网页文本。这里我用的是Python3中的requests库,提交一个包含URL的request请求,会返回一个包含网页内容的response响应。在这个response对象中就可以获取网页文本。

    3.      得到网页文本后通过一定的工具对其进行解析,得到我们感兴趣的内容(“弱水三千,我只取一瓢”那么多内容都爬下来也理解不了啊。)这里我用过的工具主要有三种,适用于不同的网页。

    (1) 对于简单一点的网页(内容不多,格式也不是标准的html格式),使用正则表达式库re,将网页视为一个超级长的字符串,匹配得到相应的内容。

    (2) 大型网站的网页,有时候用正则就会显得力不从心。另一方面,这些网页通常都是标准的html格式,而Python第三方库BeautifulSoup非常适合解决这类的问题。BeautifulSoup将整个html文档解析为以标签为节点的树形结构,并提供访问这些节点的API,这对于爬取我们关心的网页内容来讲是非常便利的。

    (3) JSON或者类JSON类型的网页,这些网页的数据全部或者大部分是以JSON格式保存的,而json库可以方便地从这些类型的网页中获取键值对等信息。

    (4) 未完待续….

    有了思路后,马上进行京东手机爬取的内容吧~

    1.      进入京东的首页,选择手机后的界面是这样式儿的:

    得到这些URL后,先选择某一页查看源代码找到我们关心的内容:

    好,170页,这就是我们的目标。而我们更关心每页的URL,这就有点像找规律了…

    第1页:

    https://list.jd.com/list.html?cat=9987,653,655&page=1&sort=sort%5Frank%5Fasc&trans=1&JL=6_0_0#J_main

    第2页:

    https://list.jd.com/list.html?cat=9987,653,655&page=2&sort=sort%5Frank%5Fasc&trans=1&JL=6_0_0#J_main

    第3页:

    https://list.jd.com/list.html?cat=9987,653,655&page=3&sort=sort%5Frank%5Fasc&trans=1&JL=6_0_0#J_main

    第170页:

    https://list.jd.com/list.html?cat=9987,653,655&page=170&sort=sort%5Frank%5Fasc&trans=1&JL=6_0_0#J_main

    看到这么有规律的URL对于程序的循环抓取来讲可是太开心了,所以京东手机预览界面的URL格式为:

    https://list.jd.com/list.html?cat=9987,653,655&page=?&sort=sort%5Frank%5Fasc&trans=1&JL=6_0_0#J_main

    其中?代表页码,这里就是1-170。

             这对应的代码为:

    def getAllPages():
        allPagesUrlList = []
        singlePageUrl = ''
        for page in range(1, 171):
            if page == 2:
                singlePageUrl = 'https://list.jd.com/list.html?cat=9987,653,655&page=' \
                                + str(page) + '&sort=sort%5Frank%5Fasc&trans=1&JL=6_0_0&ms=6#J_main'
            singlePageUrl = 'https://list.jd.com/list.html?cat=9987,653,655&page=' \
                            + str(page) + '&sort=sort%5Frank%5Fasc&trans=1&JL=6_0_0#J_main'
            allPagesUrlList.append(singlePageUrl)
        return allPagesUrlList
    在实际爬取时,发现有时候第二页的URL比其他页的多了&ms=6(经验证是系统随机生成的,应该是隔几天会出现一次)。这里就按照当时爬取的URL进行处理。

    得到这些URL后,先选择某一页查看源代码找到我们关心的内容:


    这里每一页都有N多个手机,我们在人工点击一个手机时会跳转到手机详情界面,而这个链接在上图的href标签内。这里采用BeautifulSoup库获取该标签的内容。代码如下:

    def getPhonesUrl(pageUrl):
        phonesUrlList = []
        html = getHtmlText(pageUrl)
        soup = BeautifulSoup(html, 'html.parser')
        items = soup.find_all('div',attrs={'class':'p-name'})
        for item in items:
            phonesUrlList.append('https:' + item.a.get('href'))
        return phonesUrlList

    查看手机详情界面的源文件可以看到,我们关心的手机名称,价格,配置,评论分别在哪呢?

    手机名称的位置:


    可以看到手机名称在<div class=’sku-name’></div>标签下,以下是获取手机名称的代码:

    手机配置的位置:


    在浏览器显示界面看到的内容:


    为了在爬取时顺序不会乱,这里用字典类型保存这些配置信息,代码如下:

    def getPhoneName(phoneurl):
        infoText = getHtmlText(phoneurl)
        soup = BeautifulSoup(infoText, 'html.parser')
        name = soup.find('div', attrs={'class': 'sku-name'}).get_text().strip()
        return name
    def getPhoneProperties(phoneurl):
        phoneProperties = {}
        list_value = []
        list_name = []
    
        infoText = getHtmlText(phoneurl)
        soup = BeautifulSoup(infoText, 'html.parser')
        proSection = soup.findAll('div', attrs={'class': 'Ptable-item'})
    
        for pro in proSection:
            # 既然找不到直接去除有属性标签的方法就取个差集吧
            list_all = pro.find_all('dd')
            list_extracted = pro.find_all('dd', {'class': 'Ptable-tips'})
            list_chosen = [i for i in list_all if i not in list_extracted]
    
            for dd in list_chosen:
                list_value.append(dd.string)
    
            for dt in pro.find_all('dt'):
                list_name.append(dt.string)
    
        for i in range(0, len(list_name)):
            phoneProperties.update({list_name[i]: list_value[i]})
    
        return phoneProperties

    爬取图片:

    首先查看网页源代码:



    这些蓝色的链接就是图片下载地址,只需保存在列表中,再进行下载即可。代码如下:

    def getPhoneImages(phoneurl):
        infoText = getHtmlText(phoneurl)
        soup = BeautifulSoup(infoText, 'html.parser')
        imgDiv = soup.find('div', attrs={'class': 'spec-items'})
        phoneImageLink = []
        for img in imgDiv.findAll('img'):
            phoneImageLink.append('https:' + img.get('src'))
        return phoneImageLink

    这时候,开始提到的那个问题出现了,这个界面没有价格信息,只有一小部分评论信息。经过查询了解到价格信息和评论信息是通过JS动态加载的,初始静态页面不显示或者显示不全。解决方法是使用浏览器的开发者模式打开页面(之前一直用的360浏览器,找了半天没找到开发者工具,坑啊……后来用了搜狗还挺方便的~)在Network里搜索price会出现获取价格的JS响应,但是拿出来的响应链接是这样的:

    https://p.3.cn/prices/mgets?callback=jQuery768325&type=1&area=1_2800_2849_0.138043016&pdtk=

    &pduid=933088261&pdpin=%25E4%25BD%25A0%25E6%2598%25AFsunshine%25E4%25B9%2588

    &pin=%E4%BD%A0%E6%98%AFsunshine%E4%B9%88&pdbp=0&skuIds=J_3846673%2CJ_3882469

    %2CJ_5005731%2CJ_3458011%2CJ_3893499%2CJ_5114365%2CJ_3728945%2CJ_4241985

    %2CJ_3479621%2CJ_3882469%2CJ_5005731%2CJ_2967927%2CJ_3882453%2CJ_3355143

    %2CJ_3907423%2CJ_4241985%2CJ_3479621%2CJ_3846673%2CJ_4460283%2CJ_3882469

    %2CJ_4095237&ext=11000000&source=item-pc

    有一点点…夸张?通过网上查询找到了个更简洁的API入口:

    https://p.3.cn/prices/mgets?skuIds=J_?

    其中?表示的就是京东手机的itemId。任意找个价格网址打开,内容是这样的:

    这么…….简单直白的网页还是少见哈哈。这种的话用正则表达式匹配就最合适了,p标签里面的值”999.00”就是我们关心的价格啦~用正则表达式把它揪出来吧:

    pattern =re.compile('"p":"(.*?)"')

    price = re.findall(pattern, priceText)[0]

    (这里简单说明一下:由于re.findall()方法返回的是由所有匹配的字符串组成的列表,这里只有第一个元素,故取索引[0]得到目标字符串,否则将得到只有一个字符串的列表。)

             到这里剩下商品的评论列表的爬取了。同样的,所有评论信息也是动态加载的,同样在开发者模式下,Network里搜索price,下拉到评论页面,会出现一个productPageComments.action…的响应,点击进去进入评论网页:

    https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv43344&productId=2888224&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1


    评论网页分为:1.评论摘要(好评数,就、好评率等等)2.用户的详细评论信息。这是个类json格式展现的网页(剔除前面和后面的文字),因此用json库进行信息提取是最合适的。这里的思路是:首先提取评论摘要信息,保存在字典中;其次,爬取所有具体的评论信息,每个用户的评论(包括用户昵称,评论时间,评论内容等等)保存在字典中,所有用户的评论保存在列表中。以下是代码:

    def getPhoneComments(phoneurl):
        phoneId = phoneurl[20:-5]
        commentStartUrl = 'https://club.jd.com/comment/productPageComments.action?callback=' \
                          'fetchJSON_comment98vv10636&productId=' + phoneId + '&score=0&sortType=5&page=0&pageSize=10'
        htmlText = getHtmlText(commentStartUrl)
        jsonText = json.loads(htmlText[27:-2])
        # 获取最大页面数便于爬取
        maxPage = jsonText['maxPage']
        # 手机评价信息概览
        commentSummaryDict = {}
        commentSummary = jsonText['productCommentSummary']
        commentSummaryDict.update({'好评率': str(commentSummary['goodRateShow']) + '%'})
        commentSummaryDict.update({'评论数': commentSummary['commentCountStr']})
        commentSummaryDict.update({'晒图': jsonText['imageListCount']})
        commentSummaryDict.update({'追评数': commentSummary['afterCountStr']})
        commentSummaryDict.update({'好评数': commentSummary['goodCountStr']})
        commentSummaryDict.update({'中评数': commentSummary['generalCountStr']})
        commentSummaryDict.update({'差评数': commentSummary['poorCountStr']})
    
        # 获取全部的评价内容
        userCommentList = []
        for commentPage in range(0, maxPage):
            commentPageUrl = 'https://club.jd.com/comment/productPageComments.action?callback=' \
                             'fetchJSON_comment98vv10636&productId=' + phoneId + '&score=0&sortType=5&' \
                             'page=' + str(commentPage) + '&pageSize=10'
            commentHtmlText = getHtmlText(commentPageUrl)
            # 评论可多可少,出错就直接跳过
            try:
                commentJsonText = json.loads(commentHtmlText[27:-2])
                comments = commentJsonText['comments']
    
                for comment in comments:
                    commentsInfo = {}
                    commentsInfo.update({'昵称': comment['nickname']})
                    commentsInfo.update({'用户等级': comment['userLevelName']})
                    commentsInfo.update({'评论星级': str(comment['score']) + '星'})
                    commentsInfo.update({'内容': comment['content']})
                    commentsInfo.update({'机型': comment['productColor'] + ',' + comment['productSize']})
                    commentsInfo.update({'发表时间': comment['creationTime']})
                    commentsInfo.update({'点赞数': comment['usefulVoteCount']})
                    commentsInfo.update({'评论回复次数': comment['replyCount']})
                    commentsInfo.update({'是否推荐': changeRecommnedType(comment['recommend'])})
                    commentsInfo.update({'客户端': comment['userClientShow']})
    
                    userCommentList.append(commentsInfo)
            except:
                continue
            print('******正在爬取第'+str(commentPage)+'页评论')
    
        return commentSummaryDict, userCommentList

    我们需要的内容都已经获取完毕,接下来就是保存到文件里面,为将来数据分析做准备:

    创建一个根目录,一级子目录生成以手机名称命名的文件夹,所有手机信息爬取完毕后再生成包含所有手机信息的csv文件。每个手机文件夹下的二级子目录保存评论信息和配置信息的csv文件,以及存放图片的文件夹,该文件夹下的三级子目录存放下载的手机图片。以下是结构图:


    讲了这么多,再用一张图理一下思路:


    最后附上所有代码:

    import requests
    from bs4 import BeautifulSoup
    import re
    import json
    import csv
    import os
    import sys
    import io
    import time
    from collections import OrderedDict
    
    # 通过URL获取网页文本
    def getHtmlText(url):
        proxies = {'http': '114.217.129.128	8998'}
        # 使用伪装浏览器和代理IP(被封了就惨了)
        r = requests.get(url, headers={'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)'}, proxies = proxies)
        r.encoding = r.apparent_encoding
        return r.text
    
    # 将网页原生的是否推荐的True和False替换为是和否
    def changeRecommnedType(inputBool):
        if inputBool == True:
            return '是'
        else:
            return '否'
    
    # 生成手机1-170页的url列表(最初调用一次,全局使用)
    def getAllPages():
        allPagesUrlList = []
        singlePageUrl = ''
        for page in range(1, 171):
            if page == 2:
                singlePageUrl = 'https://list.jd.com/list.html?cat=9987,653,655&page=' \
                                + str(page) + '&sort=sort%5Frank%5Fasc&trans=1&JL=6_0_0&ms=6#J_main'
            singlePageUrl = 'https://list.jd.com/list.html?cat=9987,653,655&page=' \
                            + str(page) + '&sort=sort%5Frank%5Fasc&trans=1&JL=6_0_0#J_main'
            allPagesUrlList.append(singlePageUrl)
        return allPagesUrlList
    
    
    # 在手机概览界面网页获取手机详细信息链接
    def getPhonesUrl(pageUrl):
        phonesUrlList = []
        html = getHtmlText(pageUrl)
        soup = BeautifulSoup(html, 'html.parser')
        items = soup.find_all('div',attrs={'class':'p-name'})
        for item in items:
            phonesUrlList.append('https:' + item.a.get('href'))
        return phonesUrlList
    
    # 获取手机价格
    def getPhonePrice(phoneurl):
        # 由于价格不在主页面显示,通过抓包找到显示价格的网址,以物品编号为区别特征
        priceUrl = 'https://p.3.cn/prices/mgets?skuIds=J_' + phoneurl[20:-5]
        priceText = getHtmlText(priceUrl)
        pattern = re.compile('"p":"(.*?)"')
        price = re.findall(pattern, priceText)[0]
        return price
    
    # 获取手机名称
    def getPhoneName(phoneurl):
        infoText = getHtmlText(phoneurl)
        soup = BeautifulSoup(infoText, 'html.parser')
        name = soup.find('div', attrs={'class': 'sku-name'}).get_text().strip()
        return name
    
    # 获取手机图片链接(-----还要加下载的方法-----)
    def getPhoneImages(phoneurl):
        infoText = getHtmlText(phoneurl)
        soup = BeautifulSoup(infoText, 'html.parser')
        imgDiv = soup.find('div', attrs={'class': 'spec-items'})
        phoneImageLink = []
        for img in imgDiv.findAll('img'):
            phoneImageLink.append('https:' + img.get('src'))
        return phoneImageLink
    
    # 获取手机的属性信息
    def getPhoneProperties(phoneurl):
        phoneProperties = {}
        list_value = []
        list_name = []
    
        infoText = getHtmlText(phoneurl)
        soup = BeautifulSoup(infoText, 'html.parser')
        proSection = soup.findAll('div', attrs={'class': 'Ptable-item'})
    
        for pro in proSection:
            # 既然找不到直接去除有属性标签的方法就取个差集吧
            list_all = pro.find_all('dd')
            list_extracted = pro.find_all('dd', {'class': 'Ptable-tips'})
            list_chosen = [i for i in list_all if i not in list_extracted]
    
            for dd in list_chosen:
                list_value.append(dd.string)
    
            for dt in pro.find_all('dt'):
                list_name.append(dt.string)
    
        for i in range(0, len(list_name)):
            phoneProperties.update({list_name[i]: list_value[i]})
    
        return phoneProperties
    
    # 获取该买该手机的评论信息
    def getPhoneComments(phoneurl):
        phoneId = phoneurl[20:-5]
        commentStartUrl = 'https://club.jd.com/comment/productPageComments.action?callback=' \
                          'fetchJSON_comment98vv10636&productId=' + phoneId + '&score=0&sortType=5&page=0&pageSize=10'
        htmlText = getHtmlText(commentStartUrl)
        jsonText = json.loads(htmlText[27:-2])
        # 获取最大页面数便于爬取
        maxPage = jsonText['maxPage']
        # 手机评价信息概览
        commentSummaryDict = {}
        commentSummary = jsonText['productCommentSummary']
        commentSummaryDict.update({'好评率': str(commentSummary['goodRateShow']) + '%'})
        commentSummaryDict.update({'评论数': commentSummary['commentCountStr']})
        commentSummaryDict.update({'晒图': jsonText['imageListCount']})
        commentSummaryDict.update({'追评数': commentSummary['afterCountStr']})
        commentSummaryDict.update({'好评数': commentSummary['goodCountStr']})
        commentSummaryDict.update({'中评数': commentSummary['generalCountStr']})
        commentSummaryDict.update({'差评数': commentSummary['poorCountStr']})
    
        # 获取全部的评价内容
        userCommentList = []
        for commentPage in range(0, maxPage):
            commentPageUrl = 'https://club.jd.com/comment/productPageComments.action?callback=' \
                             'fetchJSON_comment98vv10636&productId=' + phoneId + '&score=0&sortType=5&' \
                             'page=' + str(commentPage) + '&pageSize=10'
            commentHtmlText = getHtmlText(commentPageUrl)
            # 评论可多可少,出错就直接跳过
            try:
                commentJsonText = json.loads(commentHtmlText[27:-2])
                comments = commentJsonText['comments']
    
                for comment in comments:
                    commentsInfo = {}
                    commentsInfo.update({'昵称': comment['nickname']})
                    commentsInfo.update({'用户等级': comment['userLevelName']})
                    commentsInfo.update({'评论星级': str(comment['score']) + '星'})
                    commentsInfo.update({'内容': comment['content']})
                    commentsInfo.update({'机型': comment['productColor'] + ',' + comment['productSize']})
                    commentsInfo.update({'发表时间': comment['creationTime']})
                    commentsInfo.update({'点赞数': comment['usefulVoteCount']})
                    commentsInfo.update({'评论回复次数': comment['replyCount']})
                    commentsInfo.update({'是否推荐': changeRecommnedType(comment['recommend'])})
                    commentsInfo.update({'客户端': comment['userClientShow']})
    
                    userCommentList.append(commentsInfo)
            except:
                continue
            print('******正在爬取第'+str(commentPage)+'页评论')
    
        return commentSummaryDict, userCommentList
    
    # 将手机的特征添加到一起
    def getPhoneInfo(phoneurl):
        phoneInfo = {}
        price = getPhonePrice(phoneurl)
        phoneInfo.update({'价格':price})  # 字符串
        name = getPhoneName(phoneurl)
        phoneInfo.update({'名称': name})  # 字符串
        phoneImageLink = getPhoneImages(phoneurl)
        phoneInfo.update({'图片链接':phoneImageLink})   # 字符串列表
        phoneProperties = getPhoneProperties(phoneurl)
        phoneInfo.update({'手机配置':phoneProperties})  #  字典
        commentSummaryDict, userCommentList = getPhoneComments(phoneurl)
        phoneInfo.update({'手机整体评价':commentSummaryDict})    # 字典
        phoneInfo.update({'手机全部评价内容':userCommentList})    # 元素是字典的列表
    
        return phoneInfo
    
    if __name__ == '__main__':
        url = 'https://list.jd.com/list.html?cat=9987,653,655&page=1&sort=sort%5Frank%5Fasc&trans=1&JL=6_0_0#J_main'
        rootPath = 'E:/JDPhones/'
        phoneInfoAll = []
    
        phoneUrls = getPhonesUrl(url)
        # 程序开始时间
        startTime = time.clock()
    
        for phoneurl in phoneUrls:
            print('正在爬取第', str(phoneUrls.index(phoneurl) + 1), '部手机......')
    
            info = getPhoneInfo(phoneurl)
            phoneInfoAll.append(info)
    
            phoneName = info['名称']
            phoneImaLink = info['图片链接']
    
            # 创建文件夹(先判断是否存在,因为有重复的手机)
            dirPathToMake = rootPath + phoneName + '/' + 'images/'
            if os.path.exists(dirPathToMake):
                continue
            else:
                os.makedirs(dirPathToMake)
            # 将图片下载到本地
            for link in phoneImaLink:
                imgHtml = requests.get(link, stream=True, headers={
                    'User-Agent': 'User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) '
                                  'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari'
                                  '/537.36 SE 2.X MetaSr 1.0'}, proxies={'http': '114.217.129.128 8998'})
                imgHtml.encoding = imgHtml.apparent_encoding
    
                with open(rootPath + phoneName + '/' + 'images/'+ str(phoneImaLink.index(link)) + '.jpg', 'wb') as wimg:
                    wimg.write(imgHtml.content)
            # 写入配置信息
            phoneProperties = info['手机配置']
            with open(rootPath + phoneName + '/' + 'properties.csv', 'w', newline='', encoding='gb18030') as wpro:
                writer = csv.writer(wpro)
                for key in phoneProperties.keys():
                    writer.writerow([key, phoneProperties[key]])
            # 写入评论
            commentsHeader = ['昵称', '用户等级', '评论星级', '内容', '机型', '发表时间', '点赞数', '评论回复次数',
                              '是否推荐', '客户端']
            userCommentList = info['手机全部评价内容']
            with open(rootPath + phoneName + '/' + 'comments.csv', 'w', newline='', encoding='gb18030') as wcom:
                writer = csv.writer(wcom)
                writer.writerow(commentsHeader)
                for comment in userCommentList:
                        tempList = []
                        for commentInfo in commentsHeader:
                            tempList.append(comment[commentInfo])
                        writer.writerow(tempList)
    
        #  去除列表中的重复元素(不保持顺序)
        #  保持顺序的做法:phoneInfoAll = list(OrderedDict.fromkeys(phoneInfoAll))
        phoneInfoAll = list(set(phoneInfoAll))
    
        # 爬取所有手机信息后,做一个整体的统计分析
        headers = ['名称', '价格', '好评率', '评论数', '晒图', '追评数', '好评数', '中评数', '差评数']
        with open('E:/JDPhones/AllPhonesInfo.csv', 'a', newline='', encoding='gb18030') as file:
            fwriter = csv.writer(file)
            fwriter.writerow(headers)
            for phone in phoneInfoAll:
                # print(phone)
                phoneInfoList = [phone['名称'], phone['价格'], phone['手机整体评价']['好评率'], phone['手机整体评价']['评论数'],
                                 phone['手机整体评价']['晒图'], phone['手机整体评价']['追评数'], phone['手机整体评价']['好评数'],
                                 phone['手机整体评价']['中评数'], phone['手机整体评价']['差评数']]
                fwriter.writerow(phoneInfoList)
        # 程序结束时间
        endTime = time.clock()
        print('所有手机爬取完毕,程序耗费的时间为:', endTime-startTime)
    
    
    
    
    
    
    
    (PS:这样的内容爬取起来太慢了,170页,每页63个手机,每个手机100条评论.......亲测爬取一页手机要将近40Mins,在最后阶段研究多线程并行爬取没有好的效果,暂时先这样,有好的批处理的方法后再来更新。另外,价格的URL在爬完100页后出现错误无法访问,出去几天回来又好了,不是大问题,简单mark一下就好。)

    展开全文
  • 之前介绍的都是关于网页爬虫的相关内容,今天博主想跟大家分享一个非常牛的手机爬虫工具Appium,首先我会介绍它的安装方法,然后给出一个Appium连接手机app例程。 二.详细安装过程 2.1 Node.js的安装 进入Node.js...

    一.前言

    之前介绍的都是关于网页爬虫的相关内容,今天博主想跟大家分享一个非常牛的手机爬虫工具Appium,首先我会介绍它的安装方法,然后给出一个Appium连接手机app例程。

    二.详细安装过程

    2.1 Node.js的安装

    进入Node.js官网下载相应的软件,我选择的是左侧的更稳定的版本14.15.4,下载完成后点击安装,在安装过程中所有的步骤全部按默认即可。

    nodejs

    2.2 JDK8的安装

    首先需要选择对合适的JDK版本,我之前安装的是JDK11,结果在安装SDK工具的时候被识别JDK版本过低而安装失败,经过上网查询可知原来SDK只支持JDK8,因此建议一定要装好JDK8。鉴于如今甲骨文下载JDK需要有账号才可以,为了方便大家这里提供一个百度网盘的下载地址,提取码为qgnu 。下载完成后,按照常规的JDK安装步骤进行下去即可,这里不做详细的介绍。

    2.3 SDK Tool的安装

    该工具好像官方不提供单独的下载包了,目前有两种解决策略:

    • 直接下载Android Studio,其内部包含了SDK工具,但是比较大。
    • 网上某些大佬提供之前的资源

    我选择的是后者,打开上述连接,在Android SDK工具中点击SDK Tools即可看到下面的界面:

    SDK

    根据自己的平台选择对应版本的SDK工具,我选择的是Windows平台的exe版本,点击下载后,双击进行安装。在安装过程中有几个注意事项。首先在选择用户的时候,要选择Install for anyone using this computer,在Android SDK Manager界面只需要选择下载Android SDK ToolsAndroid SDK Platform-toolsAndroid SDK Build-tools三项即可(其他可有可无),具体见下图。

    usec

    downloadoption

    安装完后需要配置环境变量,首先创建新的环境变量名ANDROID_HOME,其变量值为sdk安装目录下的android-sdk文件夹,默认为 :

    C:\Program Files (x86)\Android\android-sdk
    

    然后在系统变量Path中添加环境变量%ANDROID_HOME%\tools%ANDROID_HOME%\platform-tools,完成后在命名行中输入adb version,若看到下图所示的信息即说明安装成功了。

    adbv

    2.4 Appium的安装

    在完成上述组件的安装后,最后便是Appium的下载安装了,首先去官网选择正确的版本下载,然后点击安装即可,注意在安装选项中最好选择为使用这台电脑的任何人安装,至此Appium的运行环境就搭建好了。

    三.连接例程

    这里将为大家演示一个服务端连接真机的例子,手机品牌为Redmi,Android版本为11。首先在手机上打开开发者选项,然后将USB调试USB调试安全设置设置为开启状态,即

    开发者选项

    然后将手机用USB线连接到电脑上,清空后台所有程序,打开微信,在电脑上打开命令行,先输入adb devices查看设备名,如图:

    device

    然后,输入adb shell,然后输入命令dumpsys window | grep "mCurrentFocus",可以看到如下信息:

    adbshell

    然后打开appium并开启服务器,在下面的界面中点击放大镜图标,

    open

    然后在新打开的界面中填入之前获取的这些信息如设备名、手机系统版本号、平台名(系统名)等:

    infow

    在填完上述信息后,点击右下角的Start Session即可看到成功连接的界面如下:

    success

    可以看到我们可以通过点击界面中相应的元素然后在右侧看到它的id和xpath等信息,这样我们之后就能像Selenium一样通过编写脚本来进行app的自动化控制和爬虫操作了。

    四.结语

    以上便是本文的全部内容,本文主要介绍了appium工具的安装与测试,后续将会在此基础上继续为大家带来一些手机爬虫实战项目,要是大家觉得不错的话就点个赞或关注一下吧,你们的支持是博主继续创作的不竭动力,当然若是有任何问题也敬请批评指正。

    展开全文
  • 手机上写个小爬虫

    2022-07-10 19:07:44
    基于qpython的手机爬虫编写与执行,实现小规模数据爬取。
  • 这时候正好被推荐了PCOnline上的手机详细参数,突发奇想闲着没事用Python写了一个整理手机详细信息的脚本。 工具 1. python 语言和解释器 2. python 的requests,BeautifulSoup4,xlwt(因为朋友希望整合成excel...
  • 抓取超级课程表话题数据。#!/usr/local/bin/python2.7# -*- coding: utf8 -*-"""超级课程表话题抓取"""import urllib2from cookielib import CookieJarimport json''' 读Json数据 '''def fetch_data(json_data):data...
  • Python爬虫:爬取手机App数据,记得安装配置Charles

    千次阅读 多人点赞 2021-07-31 12:17:26
    目录Python爬虫配置Charles设置手机代理服务器安装证书安装PC证书安装Android手机证书 Python爬虫 对于现在的爬虫程序来说,PC端网页数据往往并不理想。比如就拿CSDN来说,一篇帖子是否上热榜其根据的是App端数据,...
  • 实例如下所示: __author__ = 'Fred Zhao' import requests from bs4 import BeautifulSoup import os from urllib.request import urlretrieve class Picture(): def __init__(self): self.headers = {'User-...
  • 爬取手机界面的所有手机评论列表 存储到MONGODB 步骤 获取首页的手机列表,并获取各个手机标题和详情页的URL 把第1步获取的详情页URL分别打开,并获取产品ID 根据产品ID结合URL,组合出评论页的JSON请求并...
  • 在学习爬虫进阶路上少不了用到一些抓包工具,今天就给大家隆重推荐6款爬虫抓包神器。 聊一聊:爬虫抓包原理 爬虫的基本原理就是模拟客户端(可以是浏览器,也有可能是APP)向远程服务器发送 HTTP 请求,我们需要知道...
  • 今天要说说怎么在我们的手机抓包...我们经常在用的手机手机里面的数据怎么对它抓包呢?那么...接下来就是学习 python 的正确姿势我们要用到一款强大免费的抓包工具Fiddler你可以到https://www.telerik.com/download/...
  • 1.下载最新版Fiddler,强烈建议在官网下载:https://www.telerik.com/download/fiddler 2.正常傻瓜式安装,下一步,下一步,安装完毕后,先不用急于打开软件。3.下载并安装Fiddler证书生成器:...Options ...
  • 安卓手机上运行Python爬虫

    千次阅读 2020-10-08 15:44:01
    在软件市场搜索下载安装即可, 这个软件可以让你把手机当Linux电脑使用, 除了屏幕小点儿. 为了敲命令方便, 建议安装输入法: CodeBoard, 功能键几乎都有了 参考自安卓手机运行python程序的软件:Termux 注: py是因为用...
  • 基于python实现的某东手机评论数据采集与分析爬虫
  • Python爬虫抓取手机APP的传输数据,python爬虫抓取app大多数APP里面返回的是json格式数据,或者一堆加密过的数据 。这里以超级课程表APP为例,抓取超级课程表里用户发的话题。1、抓取APP数据包方法详细可以参考这篇...
  • 我们用手机进行爬取APP时,进行参数配置时会出现下面情况: 百度: 1.![不行,链接直达:](https://img-blog.csdnimg.cn/20200304000921537.png) 2.![灵感,链接直达:]...
  • 如题,首先当然是要打开京东的手机页面 因为要获取不同页面的所有手机图片,所以我们要跳转到不同页面观察页面地址的规律,这里观察第二页页面 由观察可以得到,第二页的链接地址很有可能是 ...
  • 淘宝、京东反反爬虫爬取手机信息 应对反爬的方式:使用 selenium 模拟浏览器方式爬取,先通过以某个端口打 开 chrome 浏览器,手动登录淘宝,防止留下 selenium 指纹被淘宝封号: 再通过 9399 端口将浏览器控制...
  • python爬虫入门 之 移动端数据的爬取

    千次阅读 2020-12-28 21:24:47
    就可以让fiddler捕获手机发起的http和https的请求 7.2 scrapy ,pyspider #总结: ​#爬虫文件中的属性和方法 name :爬虫文件唯一标识 start_url:该列表中的url会被自动的进行请求发送#自动请求发送的过程: defstart_...
  • 手机淘宝App 闲鱼App 相关爬虫
  • 项目上需要用到手机号前7位,判断号码是否合法,还有归属地查询。旧的数据是几年前了太久了,打算用python爬虫重新爬一份 单线程版本 # coding:utf-8 import requests from datetime import datetime class ...
  • 可以查看这篇文章配置:如果要抓取https包,还需要安装这个证书:启动mitmproxymitm.it,选择匹配的证书下载安装(见下图),设置=》安全=》信任的凭据=》用户。
  • 京东全网手机爬虫scrapy_redis及决策树数据分析 参考了实验楼并进行延伸 SqlServer版本:13.0.1742.0 (也可使用mongodb) Python版本3.7.1 软件:Pycharm , Navicat , SSMS,RedisDesktopManager 项目架构: 爬虫...
  • 从40篇博客开始,我将逐步讲解一下手机APP的爬虫,关于这部分,我们尽量简化博客内容,在这部分中可能涉及到一些逆向,破解的内容,这部分尽量跳过,毕竟它涉及的东西有点复杂,并且偏离了爬虫体系太远,有兴趣的...
  • 本文介绍了多任务端app应用数据抓取。如果觉得文章对你有用处,记得转发一波哦,博主也支持为铁粉丝制作专属动态壁纸哦~

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 31,162
精华内容 12,464
关键字:

手机爬虫

友情链接: PDAGPS.rar