精华内容
下载资源
问答
  • 微信公众号爬虫

    2019-01-30 18:14:32
    用python爬取微信公众号内容 主要内容: 爬虫基本原理 爬虫工具 Requests 的基本使用 数据抓包分析工具 Fiddler 的基本使用 MongoDB 数据库的基本使用 使用 Pandas 进行数据分析 使用 Matplotlib 进行数据可视化展示
  • GitHub 微信公众号爬虫推荐 本文推荐 GitHub 微信公众号爬虫article_spider 。 微信公众号爬虫有别于一般的网页爬虫,由于是一个相对封闭的内容平台,入口比较少,所以难度就有点大了。大概查找了一下,发觉基本上不...
  • 基于搜狗微信搜索的微信公众号爬虫接口 我的另外一个作品: ,基于代码生成的 Lark/飞书 Go SDK,欢迎 star 。
  • 基于搜狗微信搜索的微信公众号爬虫接口
  • 基于搜狗微信搜索的微信公众号爬虫接口demo
  • 基于 Python 实现微信公众号爬虫 『课程目录』: 0微信公众号爬虫的基本原理 1使用 Requests 实现一个简单网页爬虫 2使用 Fiddler 抓包分析公众号请求过程 3抓取微信公众号第一篇文章 4...
  • 基于搜狗微信搜索的微信公众号爬虫接口
  • 基于搜狗微信搜索的微信公众号爬虫 可以抓取指定公众号的文章信息到mysql数据库。对sogo和微信验证码,调用ruokuai接口进行识别。 项目使用: 一、使用说明 1、在mysql数据库中创建数据库,sql语句见gongzhonghao....
  • 基于搜狗搜索的微信公众号爬虫,使用requests模块访问公众号url链接,爬取相关文章(不能商用,要申请公众号主体同意方可进行相关操作),并用bs4模块解析获取的文章,并取得其中的合法内容
  • 基于node的微信公众号爬虫插件 #使用说明 test.js为启动文件 在cmd通过node test.js 命令启动 #介绍 非常简单的微信公众号爬虫功能。 1、通过搜狗微信搜索公众号,获取第一个公众号信息(例如python) 2、进入公众号...
  • # 项目简介 基于搜狗微信搜索的微信公众号爬虫 可以抓取指定公众号的文章信息
  • 微信公众号爬虫项目(reptile)

    千次阅读 多人点赞 2020-07-25 09:45:07
    个人在业余时间,写的一个以微信公众号爬虫为主要功能,普通网页爬虫、浏览器控制、邮件群发功能为辅的简单DEMO。功能简单,给开发者巨大的学习和发挥的空间。对spring boot和html有一些经验的人来说,上手简单,...

    代码仓库地址:https://gitee.com/taisan/reptile

    项目背景

    个人在业余时间,写的一个以微信公众号爬虫为主要功能,普通网页爬虫、浏览器控制、邮件群发功能为辅的简单DEMO。功能简单,给开发者巨大的学习和发挥的空间。对spring boot和html有一些经验的人来说,上手简单,学习成本低.

    功能介绍

    爬虫项目,微信公众号文章爬虫,网站文章爬虫,群发邮件系统

    项目架构

    springBoot 单项目架构

    已知爬取微信公众号有三种方法:

    第一种:用搜狗微信公众号搜过,这个只能收到前10条;(亲试,好多公众号连近10条都获取不到,放弃)

    第二种:用fiddler或手机抓包,从访问链接去获得appmsg_token,发现虽然这个值就在html页面里,但只有抓包的数据里含有效值,直接访问的是空的,而且还有时效性。这样,每次都要抓包获取,就很麻烦。

    第三种:就是这种用公众号搜公众号的,虽然速度慢点,但便捷了不少。(每天请求次数限制,约为100次)

    使用须知

    程序原理:

    通过selenium登录获取token和cookie,再自动爬取和下载

    使用前提:

    1、修改项目中Chrome驱动的路径改为自己本地的

    2、有自己的公众号,没有可以申请一个微信公众号(个人订阅版)(https://mp.weixin.qq.com)

    3、修改reptile.properties文件中的账号和密码

    安装教程

    1. git下载源码
    2. maven构建
    3. idea-java运行

    使用说明

    1. core核心包 java主方法运行
    2. spring boot 主类运行(只加载了微信公众号爬虫的定时任务)

    功能简介

    简单的爬虫系统和邮件系统 1.爬虫分为微信公众号爬虫和和普通网页爬虫(主要通过selenium和jsoup实现) 2.java邮箱发送系统,可以实现邮件群发(主要通过javax.mail实现)

    系统运行视图

    输入图片说明

    可视化页面

    输入图片说明 输入图片说明 输入图片说明

    技术交流&问题反馈

      联系QQ:1334512682 
      微信号:vxhqqh

     捐赠 

    展开全文
  • 需求 某某微信公众号历史的所有文章的阅读数和点赞数 难点 微信公众号历史的所有文章(来源???) 每篇文章的阅读量和点赞量(电脑上浏览文章只显示内容,没有阅读量、点赞量、评论……) 突破难点一 搜狗微信...

    项目实现地址。查看我的Github地址

    支持下载微信公众号内容为HTML(含图片,经过二次处理可以转换为Word、PDF),详情见GItHub。联系方式见评论。

    原文代码由于时间久远,不一定能正确运行。若要正确运行,请参考Github代码

    部分数据示例(由于数据量较大,数据可能需要几秒钟才能加载出来,请耐心等待):https://data.wnma3mz.cn/

    追踪公众号文章(仅支持标题和链接一些基本数据),日更两次,https://data.wnma3mz.cn/demo.html

    目前具体可获取指标(包含但不局限):阅读数、点赞数(在看)、评论内容及总数、正文内容及图片、是否为头条、是否为原创。
    在这里插入图片描述

    项目已经实现,比本文介绍的更加方便简单,可直接调用。

    关于批量关注公众号的问题已解决,见我的另一篇csdn文章:自动批量关注微信公众号(非逆向)

    不求完美,只求能够用。。。

    截至2020年10月项目可正常运行, 方法已更新。

    3月1号更新:

    1. 获取阅读点赞时,每篇文章间隔10s 一次性可获取500篇文章以上
    2. 从公众号获取永久链接时,间隔3分钟,可以连续获取几小时(网友测试)

    公开已爬取的公众号历史文章的永久链接,数据上传至GitHub,日期均截止commit时间。

    需求

    某某微信公众号历史的所有文章的阅读数和点赞数

    难点

    1. 微信公众号历史的所有文章(来源???)
    2. 每篇文章的阅读量和点赞量(电脑上浏览文章只显示内容,没有阅读量、点赞量、评论……)

    突破难点一

    1. 搜狗微信搜索,可以搜索微信公众号文章。但是貌似只能显示该公众号最近十篇的文章。放弃……
    2. 利用抓包工具(Fiddler),抓取文章。成本有点大……,且貌似只能抓取原创文章。不符合个人需求,放弃……
    3. 利用微信个人订阅号进行爬取,神奇的操作。

    操作

    1. 拥有一个微信个人订阅号,附上登陆和注册链接。微信公众平台

    2. 好在之前无聊注册过一次,所以就可以直接登陆操作。没有注册的童鞋可以用自己的微信号注册一下,过程十分简单,在此就不赘述了

    3. 登陆之后,点击左侧菜单栏“管理”-“素材管理”。再点击右边的“新建图文素材”

    pic1

    1. ​弹出一个新的标签页,在上面的工具栏找到“超链接”并点击
      pic2

    2. 弹出了一个小窗口,选择“查找文章”,输入需要查找的公众号,这里用“科技美学”公众号作为例子
      pic3

    3. 点击之后,可以弹出该公众号的所有历史文章

    pic4

    代码实现

    # -*- coding: utf-8 -*-
    import requests
    import time
    import json
    
    
    # 目标url
    url = "https://mp.weixin.qq.com/cgi-bin/appmsg"
    
    # 使用Cookie,跳过登陆操作
    headers = {
      "Cookie": yourcookie,
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36",
    }
    
    """
    需要提交的data
    以下个别字段是否一定需要还未验证。
    注意修改yourtoken,number
    number表示从第number页开始爬取,为5的倍数,从0开始。如0、5、10……
    token可以使用Chrome自带的工具进行获取
    fakeid是公众号独一无二的一个id,等同于后面的__biz
    """
    data = {
        "token": yourtoken,
        "lang": "zh_CN",
        "f": "json",
        "ajax": "1",
        "action": "list_ex",
        "begin": number,
        "count": "5",
        "query": "",
        "fakeid": yourfakeid,
        "type": "9",
    }
    
    # 使用get方法进行提交
    content_json = requests.get(url, headers=headers, params=data).json()
    # 返回了一个json,里面是每一页的数据
    for item in content_json["app_msg_list"]:
        # 提取每页文章的标题及对应的url
        print(item["title"], "url": item["link"])
    

    以上,即可爬取微信公众号的一页数据,如果是爬取所有页的数据,则需要改变number进行爬取。

    注:每次抓取完一页之后,最好设定time.sleep(3)。过快会导致爬取失败

    突破难点二

    这里我使用的方法是在电脑上登陆微信客户端,进行抓包分析。从客户端看推文可以看到阅读量、点赞量。

    我使用的是Fiddler。Fiddller具体使用就不赘述了。下面直接演示操作

    操作

    1. 打开fiddler开始监控
    2. 登陆微信客户端,浏览该公众号的任意一篇推文
    3. 可以观察到这里的内容显示会有阅读量、点赞量、评论等
    4. 观察fiddler的监控数据,如下图显示

    pic5
    5. 其中/mp/getappmgsext?...是我们推文内容的url,双击之后,fiddler界面右边出现如下图数据

    pic6
    6. 上图下侧的json里面的read_numlike_num分别是阅读量和点赞量

    ####代码实现

    import time
    import requests
    import json
    
    
    # 目标url
    url = "http://mp.weixin.qq.com/mp/getappmsgext"
    # 添加Cookie避免登陆操作,这里的"User-Agent"最好为手机浏览器的标识
    headers = {
        "Cookie": yourcookie,
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 MicroMessenger/6.5.2.501 NetType/WIFI WindowsWechat QBCore/3.43.27.400 QQBrowser/9.0.2524.400"
    }
    
    
    data = {
        "is_only_read": "1",
        "is_temp_url": "0",                
        "appmsg_type": "9", # 新参数,不加入无法获取like_num
    }
    """
    添加请求参数
    __biz对应公众号的信息,唯一
    mid、sn、idx分别对应每篇文章的url的信息,需要从url中进行提取
    key、appmsg_token从fiddler上复制即可
    pass_ticket对应的文章的信息,貌似影响不大,也可以直接从fiddler复制
    """
    params = {
        "__biz": your__biz,
        "mid": article_mid,
        "sn": article_sn,
        "idx": article_idx,
        "key": yourkey,
        "pass_ticket": pass_ticket,
        "appmsg_token": yourappmsg_token,
    }
    # 使用post方法进行提交
    content = requests.post(url, headers=headers, data=data, params=params).json()
    
    # 由于上面这种方法可能会获取数据失败,可以采取字符串拼接这种方法
    origin_url = "https://mp.weixin.qq.com/mp/getappmsgext?"
    appmsgext_url = origin_url + "__biz={}&mid={}&sn={}&idx={}&appmsg_token={}&x5=1".format(your__biz, article_mid, article_sn, article_idx, yourappmsg_token)
    content = requests.post(appmsgext_url, headers=headers, data=data).json()
    
    # 提取其中的阅读数和点赞数
    print(content["appmsgstat"]["read_num"], content["appmsgstat"]["like_num"])
    

    以上即可获取到一篇文章的阅读量、点赞量。
    Cookiereq_idpass_ticketkeyappmsg_token__biz利用fiddler获取
    如果是需要多篇文章,需要更改的参数midsnidx
    如果是不同公众号,就需要根据url修改__biz
    多篇文章的爬取,需要根据之前爬取到的url进行提取关键信息,分别爬取。
    注:每次抓取完一页之后,最好设定time.sleep(3)。过快会导致爬取失败。

    写在最后

    以上就是这次微信爬虫的经历。

    需要掌握的基本技能:

    1. python爬虫的语法
    2. Chrome、Fiddler基本使用
    3. 网络爬虫基本常识

    缺陷:

    1. 使用Cookie登陆,未实现自动登陆
    2. key、appmsg_token一些关键参数需要进行手动获取
    3. 实际运行之后,就算设定了爬取间隙时间,还是会被封禁(获取链接时)。

    说明:

    1. 网上一些说法,key半小时过期,我好像没有遇到。
    2. 代码中若有细节问题,欢迎指出讨论

    Github上已经实现了第1、2点,欢迎回到文章开头看github上的实现过程。

    关于被封禁的问题,已有两个解决方案,均放在github上,在这不做讲解。

    1. selenium解决方案,提高约十倍抓取量(不确定)。优点:提高抓取量;缺点:速度慢,不一定能完全抓取完整,抓取量不确定。test_seleinum.py
    2. 利用个人微信号的查看公众号历史消息,抓取量在500条以上,具体未测试。优点:抓取量最多的方案;缺点:短时间内(5-10分钟)无法查看历史消息,或者说无法持续抓取;不保证微信号会被封号。test_GetUrls.py
    展开全文
  • 服务端爬取实现见:微信公众号爬虫:服务端公众号文章数据采集 背景:在团队的学习方面需要每周收集开发方面的博客文章,汇总输出每周的技术周报。周报小组成员收集的文章大多数是来自微信公众号,公众号的内容相对...

    本文内容详细介绍微信公众号历史文章自动化浏览脚本的实现,配合服务端对公众号文章数据爬取来实现微信公众号文章数据的采集。服务端爬取实现见:微信公众号爬虫:服务端公众号文章数据采集

    背景:在团队的学习方面需要每周收集开发方面的博客文章,汇总输出每周的技术周报。周报小组成员收集的文章大多数是来自微信公众号,公众号的内容相对网页博客内容质量还是比较高的。既然数据的来源是确定的,收集汇总的流程是确定的,那么就把这个流程自动化,把人工成本降低到0。

    一、方案选取

    1、数据源选取

    主要是爬取的数据来源选取,网上资料看的较多是爬取搜狗微信的内容,但是第三方平台(包括新榜、清博等 )的公众号文章数据更新做不到实时,而且数据也不全,还要和各种反爬措施斗智斗勇,浪费时间精力的事情划不来。最直接的方式当然是直接爬取微信公众号历史文章里面的内容。

    在前期预研主要参考的资料是知乎专栏:微信公众号内容的批量采集与应用

    上面的方案是借助阿里巴巴开源的AnyProxy工具,AnyProxy作为一个中间人在微信客户端和服务器之间的交互过程中做数据截获和转发。获取到公众号文章的实际链接地址之后转发到自己的服务器进行保存,整个数据采集的自动化程度较大取决于微信客户端的自动化浏览实现。

    2、自动化方案选取

    如果是比较简单的安卓应用自动化操作的实现,一般直接使用AccessibilityService就行,UIAutomator也是基于AccessibilityService来实现的,但是AccessibilityService不支持WebView的操作,因为微信公众号历史文章页面是用WebView来加载的,要实现自动化必须同时支持安卓原生和WebView两个上下文环境的操作。

    经过现有的几个自动化方案实现对比,最便利又具备极佳扩展性的方案就是使用Appium

    •     Appium是开源的移动端自动化测试框架;
    •     支持Native App、Hybird App、Web App;
    •     支持Android、iOS、Firefox OS;
    •     跨平台,可以在Mac,Windows以及Linux系统上;
    •     用Appium自动化测试不需要重新编译App;
    •     支持Java、python、ruby、C#、Objective C、PHP等主流语言;

    更多资料参考:Android自动化测试框架

    TIPS:

    也可以使用阿里巴巴开源的Macaca,Macaca支持主流的移动技术平台 iOS和Android,以及两大平台的混合运行时Webview,也支持以往的桌面端浏览器。

    Macaca是一套面向用户端软件的测试解决方案,提供了自动化驱动,环境配套,周边工具,集成方案,旨在解决终端上的测试、自动化、性能等方面的问题。

    有兴趣可以自行研究下Macaca的自动化实现,整个实现机制和用Appium是类似的。

    Macaca官网:

    https://macacajs.github.io/zh/

    Macaca GitHub:

    https://github.com/alibaba/macaca

    公众号文章爬取系统架构图

    公众号文章爬取系统架构图

     

    二、Appium安装配置(Mac)

    Appium程序的安装,我这边不是使用brew命令安装的方式,直接从BitBucket下载Appium安装包,也可以从Github上下载。这边使用BitBucket 1.5.3版本。

    Appium1.5.0之后的版本,需要在终端安装doctor,在终端输入命令:npm install -g appium-doctor,安装完毕之后,在终端输入命令:appium-doctor,查看所需的各个配置是否都已经安装配置完毕。下面是我这边在终端输出得到的结果:

    info AppiumDoctor Appium Doctor v.1.4.3
     info AppiumDoctor ### Diagnostic starting ###
     info AppiumDoctor   The Node.js binary was found at: /Users/chenwenguan/.nvm/versions/node/v8.9.3/bin/node
     info AppiumDoctor   Node version is 8.9.3
     info AppiumDoctor   Xcode is installed at: /Library/Developer/CommandLineTools
     info AppiumDoctor   Xcode Command Line Tools are installed.
     info AppiumDoctor   DevToolsSecurity is enabled.
     info AppiumDoctor   The Authorization DB is set up properly.
     WARN AppiumDoctor   Carthage was NOT found!
     info AppiumDoctor   HOME is set to: /Users/chenwenguan
     WARN AppiumDoctor   ANDROID_HOME is NOT set!
     WARN AppiumDoctor   JAVA_HOME is NOT set!
     WARN AppiumDoctor   adb could not be found because ANDROID_HOME is NOT set!
     WARN AppiumDoctor   android could not be found because ANDROID_HOME is NOT set!
     WARN AppiumDoctor   emulator could not be found because ANDROID_HOME is NOT set!
     WARN AppiumDoctor   Bin directory for $JAVA_HOME is not set
     info AppiumDoctor ### Diagnostic completed, 7 fixes needed. ###
     info AppiumDoctor 
     info AppiumDoctor ### Manual Fixes Needed ###
     info AppiumDoctor The configuration cannot be automatically fixed, please do the following first:
     WARN AppiumDoctor - Please install Carthage. Visit https://github.com/Carthage/Carthage#installing-carthage for more information.
     WARN AppiumDoctor - Manually configure ANDROID_HOME.
     WARN AppiumDoctor - Manually configure JAVA_HOME.
     WARN AppiumDoctor - Manually configure ANDROID_HOME and run appium-doctor again.
     WARN AppiumDoctor - Add '$JAVA_HOME/bin' to your PATH environment
     info AppiumDoctor ###
     info AppiumDoctor 
     info AppiumDoctor Bye! Run appium-doctor again when all manual fixes have been applied!
     info AppiumDoctor  
    

    上面打叉的都是没配置好的,在终端输入命令安装Carthage :brew install carthage  

    输入命令查看JDK安装路径:/usr/libexec/java_home -V

    1.8.0_60, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home
    
    /Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home 

    需要把上面的路径配置到环境变量中,ANDROID_HOME就是Android SDK的安装路径。

    输入命令打开配置文件: open ~/.bash_profile,在文件中添加如下内容:

    export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home  
    export PATH=$JAVA_HOME/bin:$PATH  
    export ANDROID_HOME=/Users/chenwenguan/Library/Android/sdk 
    

    输入命令让配置立即生效:source ~/.bash_profile

    更多安装配置资料可参考:Mac上搭建Appium环境过程以及遇到的问题

    TIPS:

    在首次使用Appium时可能会出现一个错误:

    Could not detect Mac OS X Version from sw_vers output: '10.13.2 

    在终端输入命令:

    grep -rl "Could not detect Mac OS X Version from sw_vers output" /Applications/Appium.app/ 

    得到如下结果:

    /Applications/Appium.app//Contents/Resources/node_modules/appium-support/lib/system.js
    /Applications/Appium.app//Contents/Resources/node_modules/appium-support/build/lib/system.js
    /Applications/Appium.app//Contents/Resources/node_modules/appium/node_modules/appium-support/lib/system.js
    /Applications/Appium.app//Contents/Resources/node_modules/appium/node_modules/appium-support/build/lib/system.js
    

    打开上面四个路径下的文件,添加当前的Appium版本参数,具体内容可参考:在Mac OS 10.12 上安装配置appium

    三、具体代码实现

    预研资料主要参考这篇博文:Appium 微信 webview 的自动化技术

    自动化实现的原理就是通过ID或者模糊匹配找到相应的控件,之后对这个控件做点击、滑动等操作。如果要对微信WebView做自动化,必须能够获取到WebView里面的对象,如果是Android原生的控件可以通过AndroidStudio里面的Android Device Monitor来查看控件的id、类名等各种属性。

    1、Android原生控件属性参数值的获取

    在AndroidStudio打开Monitor工具:Tools->Android->Android Device Monitor

    按照下图的步骤查看控件的ID等属性,后续在代码实现中会用到。

    Android Device Monitor

    Android Device Monitor

    2、WebView属性参数值的获取

    如果是在安卓真机上,需要打开WebView的调试模式才能读取到WebView的各个属性,在微信里面可以在任意聊天窗口输入debugx5.qq.com,这是微信x5内核调试页面,在信息模块中勾选打开TBS内核Inspector调试功能。

    微信X5内核调试页面

    微信X5内核调试页面

    之后还要在真机上安装Chrome浏览器,如果是在虚拟机上无需做此操作。

    接下来在Chrome浏览器中输入:chrome://inspect ,我这边使用的是虚拟机,真机上也一样,进入到公众号历史文章页面,这边就会显示相应可检视的WebView页面,点击inspect,进入到Developer Tools页面。

    chrome inspect页面

    chrome inspect页面

    如果进入到Developer Tools页面显示一片空白,是因为chrome inspect需要加载 https://chrome-devtools-frontend.appspot.com 上的资源,所以需要翻墙,把appstop.com 加入翻墙代理白名单,或者直接全局应用翻墙VPN,具体可参考:使用chrome remote debug时打开inspect时出现一片空白 

    下面是美团技术团队历史文章列表的详细结构信息,具体的文章列表项在weui-panel->weui-panel__bd appmsg_history_container->js_profile_history_container->weui_msg_card_list路径下。

    Chrome inspect查看WebView详细内容

    继续展开节点查看文章详细结构信息,这边可以看到每篇文章的ID都是以“WXAPPMSG100″开头的,类名都是“weui_media_box”开头,一开始的实现是通过模糊匹配ID来查找历史文章列表项数据,但在测试过程中出现来一个异常,后来发现,如果是纯文本类型的文章,也就是只有一段话的文章,它是没有ID的,所以不能通过ID来模糊匹配。

    公众号历史文章列表项详细结构

    公众号历史文章列表项详细结构

    之后就把现有的四种公众号文章类型都找来出来,找它们的共性,虽然ID不一定有,但是class类型值一定有,四种类型值如下,这样就可以通过class类型值来匹配查找数据了。

     * weui_media_box appmsg js_appmsg : 文章
     * weui_media_box text js_appmsg : 文本
     * weui_media_box img js_appmsg : 图片
     * weui_media_box appmsg audio_msg_primary js_appmsg playing : 语音 
    

    3、具体代码实现

    整体自动化是按照如下顺序:通讯录页面->点击公众号进入公众号列表页面->公众号列表项选择一个点击->公众号页面->公众号消息页面->点击“全部消息”进入公众号历史文章页面->根据设置的时间类型(一周之内、一个月之内、一年之内或者全部)逐个点击历史文章列表项,完毕之后返回公众号列表页面,继续下一个公众号浏览的操作;

    1)初始化

    private static AndroidDriver getDriver() throws MalformedURLException {
             DesiredCapabilities capability = new DesiredCapabilities();
    
             capability.setCapability("platformName", "emulator-5554");
             capability.setCapability("platformVersion", "4.4.4");
             capability.setCapability("deviceName", "MuMu");
    
             /**
              * 真机上platformName使用"Android"
              */
             /*
             capability.setCapability("platformName", "Android");
             capability.setCapability("platformVersion", "6.0");
             capability.setCapability("deviceName", "FRD-AL00");
             */
    
             capability.setCapability("unicodeKeyboard","True");
             capability.setCapability("resetKeyboard","True");
             capability.setCapability("app", "");
             capability.setCapability("appPackage", "com.tencent.mm");
             capability.setCapability("appActivity", ".ui.LauncherUI");
             capability.setCapability("fastReset", false);
             capability.setCapability("fullReset", false);
             capability.setCapability("noReset", true);
             capability.setCapability("newCommandTimeout", 2000);
    
             /**
              * 必须加这句,否则webView和native来回切换会有问题
              */
             capability.setCapability("recreateChromeDriverSessions", true);
    
             /**
              * 关键是加上这段
              */
             ChromeOptions options = new ChromeOptions();
             options.setExperimentalOption("androidProcess", "com.tencent.mm:tools");
             capability.setCapability(ChromeOptions.CAPABILITY, options);
    
             String url = "http://127.0.0.1:4723/wd/hub";
             mDriver = new AndroidDriver<>(new URL(url), capability);
             return mDriver;
         } 

    如果是虚拟机则platformName使用具体的虚拟机名称,如果是真机使用“Android”,platformVersion和deviceName可以使用工程安装APK之后查看详细信息,对应的参数就是显示的系统版本和设备名称。

    设备信息

    设备信息

    URL参数是在Appium里面设置的,确保”http://127.0.0.1:4723/wd/hub”字符串中的服务器地址和端口与Appium设置一致。

    Appium URL参数设置

    Appium URL参数设置

    2)列表滑动和元素获取

    不管是WebView还是Android原生ListView的滑动都需要在Android原生上下文环境下操作driver.context(“NATIVE_APP”); 滑动操作都可以通过如下代码实现,通过滑动前后的PageSource对比可以知道列表是否已经滑动到底部。

         /**
          * 滑动列表加载下一页数据
          *
          * @param driver
          * @return
          * @throws InterruptedException
          */
         private static boolean isScrollToBottom(AndroidDriver driver) throws InterruptedException {
             int width = driver.manage().window().getSize().width;
             int height = driver.manage().window().getSize().height;
    
             String beforeswipe = driver.getPageSource();
             driver.swipe(width / 2, height * 3 / 4, width / 2, height / 4, 1000);
             /**
              * 设置8s超时,网络较差情况下时间过短加载不出内容
              */
             mDriver.manage().timeouts().implicitlyWait(8000, TimeUnit.MILLISECONDS);
             String afterswipe = driver.getPageSource();
             /**
              * 已经到底部
              */
             if (beforeswipe.equals(afterswipe)) {
                 return true;
             }
             return false;
         } 

    TIPS:

    如果是Android原生的ListView读取到的数据是在屏幕上显示的数据,超过屏幕的数据是获取不到的,如果是WebView的列表获取的数据是所有已加载的数据,不管是否在屏幕显示范围内。

    获取公众号列表数据逻辑代码如下,”com.tencent.mm:id/a0y”是具体的公众号名称TextView的ID。

    List<WebElement> elementList = mDriver.findElementsById("com.tencent.mm:id/a0y"); 
    

    获取历史文章列表数据逻辑代码如下,div是节点,上面说到公众号四种类型的文章都是以’weui_media_box’类名开头的,通过模糊匹配class类名以’weui_media_box’开始的元素来过滤出所有的公众号文章列表项。

    List<WebElement> msgHistory = driver.findElements(By.xpath("//div[starts-with(@class,'weui_media_box')]")); 
    

    3)元素定位方式

    如果一定需要模糊匹配就使用By.xpath()的方式,因为Android APK应用如果有增加或减少了布局字符串资源或者控件,编译之后生成的ID可能会不一样,这边说的ID是指通过Android Device Monitor查看的布局ID,不是实际的布局代码控件id,布局控件id除非命名改动,否则不会变化。所以不同版本的微信客户端生成的ID很可能会不一样,如果要批量实现自动化最好使用模糊匹配的方式,但By.xpath()方式查找定位元素是遍历页面的所有元素,会比较耗时,也容易出现异常。

    在测试过程中执行

    driver.findElement(By.xpath("//android.widget.ImageView[@content-desc='返回']")).click(); 

    时候经常出现如下错误,改为

    driver.findElementById("com.tencent.mm:id/ht").click(); 

    异常消失,猜测原因就是因为By.xpath()方法查找比较耗时导致。

    org.openqa.selenium.WebDriverException: An unknown server-side error occurred while processing the command. (WARNING: The server did not provide any stacktrace information)
     Command duration or timeout: 1.41 seconds
     Build info: version: '2.44.0', revision: '76d78cf', time: '2014-10-23 20:02:37'
     System info: host: 'wenguanchen-MacBook-Pro.local', ip: '30.85.214.6', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.13.2', java.version: '1.8.0_112-release'
     Driver info: io.appium.java_client.android.AndroidDriver
     Capabilities [{appPackage=com.tencent.mm, noReset=true, dontStopAppOnReset=true, deviceName=emulator-5554, fullReset=false, platform=LINUX, deviceUDID=emulator-5554, desired={app=, appPackage=com.tencent.mm, recreateChromeDriverSessions=true, noReset=true, dontStopAppOnReset=true, deviceName=MuMu, fullReset=false, appActivity=.ui.LauncherUI, platformVersion=4.4.4, automationName=Appium, unicodeKeyboard=true, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}, platformName=Android, resetKeyboard=true}, platformVersion=4.4.4, webStorageEnabled=false, automationName=Appium, takesScreenshot=true, javascriptEnabled=true, unicodeKeyboard=true, platformName=Android, resetKeyboard=true, app=, networkConnectionEnabled=true, recreateChromeDriverSessions=true, warnings={}, databaseEnabled=false, appActivity=.ui.LauncherUI, locationContextEnabled=false, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}}]
     Session ID: 592813d6-7c6e-4a3c-8183-e5f93d1d3bf0
      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
      at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
      at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:204)
      at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:156)
      at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:599)
      at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:27)
      at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
      at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1)
      at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:352)
      at org.openqa.selenium.remote.RemoteWebDriver.findElementByXPath(RemoteWebDriver.java:449)
      at io.appium.java_client.DefaultGenericMobileDriver.findElementByXPath(DefaultGenericMobileDriver.java:99)
      at io.appium.java_client.AppiumDriver.findElementByXPath(AppiumDriver.java:1)
      at io.appium.java_client.android.AndroidDriver.findElementByXPath(AndroidDriver.java:1)
      at org.openqa.selenium.By$ByXPath.findElement(By.java:357)
      at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:344)
      at io.appium.java_client.DefaultGenericMobileDriver.findElement(DefaultGenericMobileDriver.java:37)
      at io.appium.java_client.AppiumDriver.findElement(AppiumDriver.java:1)
      at io.appium.java_client.android.AndroidDriver.findElement(AndroidDriver.java:1)
      at com.example.AppiumAutoScan.getArticleDetail(AppiumAutoScan.java:335)
      at com.example.AppiumAutoScan.launchBrowser(AppiumAutoScan.java:96)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
      at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
      at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
      at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
    

    如果容易出现如下异常,则是因为页面的内容还未加载完毕,可以通过

    mDriver.manage().timeouts().implicitlyWait(8000, TimeUnit.MILLISECONDS); 

    方法设置下超时等待时间,等待页面内容加载完毕,具体超时时间可自己调试看看设置一个合适的值。

    org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document
       (Session info: webview=33.0.0.0)
       (Driver info: chromedriver=2.20.353124 (035346203162d32c80f1dce587c8154a1efa0c3b),platform=Mac OS X 10.13.2 x86_64) (WARNING: The server did not provide any stacktrace information)
     Command duration or timeout: 2.41 seconds
     For documentation on this error, please visit: http://seleniumhq.org/exceptions/stale_element_reference.html
     Build info: version: '2.44.0', revision: '76d78cf', time: '2014-10-23 20:02:37'
     System info: host: 'wenguanchen-MacBook-Pro.local', ip: '30.85.214.81', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.13.2', java.version: '1.8.0_112-release'
     Driver info: io.appium.java_client.android.AndroidDriver
     Capabilities [{appPackage=com.tencent.mm, noReset=true, dontStopAppOnReset=true, deviceName=emulator-5554, fullReset=false, platform=LINUX, deviceUDID=emulator-5554, desired={app=, appPackage=com.tencent.mm, recreateChromeDriverSessions=true, noReset=true, dontStopAppOnReset=true, deviceName=MuMu, fullReset=false, appActivity=.ui.LauncherUI, platformVersion=4.4.4, automationName=Appium, unicodeKeyboard=true, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}, platformName=Android, resetKeyboard=true}, platformVersion=4.4.4, webStorageEnabled=false, automationName=Appium, takesScreenshot=true, javascriptEnabled=true, unicodeKeyboard=true, platformName=Android, resetKeyboard=true, app=, networkConnectionEnabled=true, recreateChromeDriverSessions=true, warnings={}, databaseEnabled=false, appActivity=.ui.LauncherUI, locationContextEnabled=false, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}}]
     Session ID: b5e933e1-0ddf-421d-9144-e423a7bb25b1
      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
      at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
      at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:204)
      at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:156)
      at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:599)
      at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:27)
      at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
      at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1)
      at org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:268)
      at io.appium.java_client.DefaultGenericMobileElement.execute(DefaultGenericMobileElement.java:27)
      at io.appium.java_client.MobileElement.execute(MobileElement.java:1)
      at io.appium.java_client.android.AndroidElement.execute(AndroidElement.java:1)
      at org.openqa.selenium.remote.RemoteWebElement.getText(RemoteWebElement.java:152)
      at com.example.AppiumAutoScan.getArticleDetail(AppiumAutoScan.java:294)
      at com.example.AppiumAutoScan.launchBrowser(AppiumAutoScan.java:110)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
      at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
      at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
      at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
    

    更多元素定位方法可参考官网:

    http://selenium-python.readthedocs.io/locating-elements.html#locating-by-id

    4)chromedriver相关问题

    在2017年6月微信热更新升级了X5内核之后,真机上切换到WebView上下文环境就出问题了,具体见这篇博文的评论Appium 微信 webview 的自动化技术 和 Appium 微信小程序,driver.context (“WEBVIEW_com.tencent.mm:tools”) 切换 webview 报错 看评论是通过降低chromedriver版本的方式来避免异常,但是在试过降低版本到20之后还是不行,更新到最新的版本也不行,于是放弃在真机上实现自动化,在模拟器中跑起来的速度也还可以接受。

    在真机上跑的时候,切换到WebView上下文环境,程序控制台输出no such session异常,异常信息如下:

    org.openqa.selenium.remote.SessionNotFoundException: no such session
       (Driver info: chromedriver=2.21.371459 (36d3d07f660ff2bc1bf28a75d1cdabed0983e7c4),platform=Mac OS X 10.13.2 x86_64) (WARNING: The server did not provide any stacktrace information)
     Command duration or timeout: 14 milliseconds
     Build info: version: '2.44.0', revision: '76d78cf', time: '2014-10-23 20:02:37'
     System info: host: 'wenguanchen-MacBook-Pro.local', ip: '192.168.1.102', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.13.2', java.version: '1.8.0_112-release'
     Driver info: io.appium.java_client.android.AndroidDriver
     Capabilities [{appPackage=com.tencent.mm, noReset=true, dontStopAppOnReset=true, deviceName=55CDU16C07009329, fullReset=false, platform=LINUX, deviceUDID=55CDU16C07009329, desired={app=, appPackage=com.tencent.mm, recreateChromeDriverSessions=True, noReset=true, dontStopAppOnReset=true, deviceName=FRD-AL00, fullReset=false, appActivity=.ui.LauncherUI, platformVersion=6.0, automationName=Appium, unicodeKeyboard=true, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}, platformName=Android, resetKeyboard=true}, platformVersion=6.0, webStorageEnabled=false, automationName=Appium, takesScreenshot=true, javascriptEnabled=true, unicodeKeyboard=true, platformName=Android, resetKeyboard=true, app=, networkConnectionEnabled=true, recreateChromeDriverSessions=True, warnings={}, databaseEnabled=false, appActivity=.ui.LauncherUI, locationContextEnabled=false, fastReset=false, chromeOptions={args=[], extensions=[], androidProcess=com.tencent.mm:tools}}]
     Session ID: e2e50190-398b-4fa2-bc66-db1097201e3f
      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
      at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
      at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:204)
      at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:162)
      at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:599)
      at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:27)
      at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:272)
      at org.openqa.selenium.remote.RemoteWebDriver.getPageSource(RemoteWebDriver.java:459)
      at com.example.AppiumAutoScan.getArticleDetail(AppiumAutoScan.java:238)
      at com.example.AppiumAutoScan.launchBrowser(AppiumAutoScan.java:78)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
      at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
      at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
      at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
    

    在Appium端输出的异常信息如下:

    [debug] [AndroidDriver] Found webviews: ["WEBVIEW_com.tencent.mm:tools","WEBVIEW_com.tencent.mm"]
     [debug] [AndroidDriver] Available contexts: ["NATIVE_APP","WEBVIEW_com.tencent.mm:tools","WEBVIEW_com.tencent.mm"]
     [debug] [AndroidDriver] Connecting to chrome-backed webview context 'WEBVIEW_com.tencent.mm:tools'
     [debug] [Chromedriver] Changed state to 'starting'
     [Chromedriver] Set chromedriver binary as: /Applications/Appium.app/Contents/Resources/node_modules/appium/node_modules/appium-android-driver/node_modules/appium-chromedriver/chromedriver/mac/chromedriver
     [Chromedriver] Killing any old chromedrivers, running: pkill -15 -f "/Applications/Appium.app/Contents/Resources/node_modules/appium/node_modules/appium-android-driver/node_modules/appium-chromedriver/chromedriver/mac/chromedriver.*--port=9515"
     [Chromedriver] No old chromedrivers seemed to exist
     [Chromedriver] Spawning chromedriver with: /Applications/Appium.app/Contents/Resources/node_modules/appium/node_modules/appium-android-driver/node_modules/appium-chromedriver/chromedriver/mac/chromedriver --url-base=wd/hub --port=9515 --adb-port=5037
     [Chromedriver] [STDOUT] Starting ChromeDriver 2.21.371459 (36d3d07f660ff2bc1bf28a75d1cdabed0983e7c4) on port 9515
     Only local connections are allowed.
     [JSONWP Proxy] Proxying [GET /status] to [GET http://127.0.0.1:9515/wd/hub/status] with no body
     [Chromedriver] [STDERR] [warn] kq_init: detected broken kqueue; not using.: Undefined error: 0
     [JSONWP Proxy] Got response with status 200: "{\"sessionId\":\"\",\"stat...
     [JSONWP Proxy] Proxying [POST /session] to [POST http://127.0.0.1:9515/wd/hub/session] with body: {"desiredCapabilities":{"ch...
    
    [JSONWP Proxy] Got response with status 200: {"sessionId":"166cee263fc87...
    
    [debug] [Chromedriver] Changed state to 'online'
     [MJSONWP] Responding to client with driver.setContext() result: null
     [HTTP] <-- POST /wd/hub/session/82b9d81c-f725-473d-8d55-ddbc1f92c100/context 200 903 ms - 76 
     [HTTP] --> GET /wd/hub/session/82b9d81c-f725-473d-8d55-ddbc1f92c100/context {}
     [MJSONWP] Calling AppiumDriver.getCurrentContext() with args: ["82b9d81c-f725-473d-8d55-d...
     [MJSONWP] Responding to client with driver.getCurrentContext() result: "WEBVIEW_com.tencent.mm:tools"
     [HTTP] <-- GET /wd/hub/session/82b9d81c-f725-473d-8d55-ddbc1f92c100/context 200 2 ms - 102 
     [HTTP] --> GET /wd/hub/session/82b9d81c-f725-473d-8d55-ddbc1f92c100/source {}
     [MJSONWP] Driver proxy active, passing request on via HTTP proxy
     [JSONWP Proxy] Proxying [GET /wd/hub/session/82b9d81c-f725-473d-8d55-ddbc1f92c100/source] to [GET http://127.0.0.1:9515/wd/hub/session/166cee263fc8757cbcb5576a52f7229e/source] with body: {}
     [JSONWP Proxy] Got response with status 200: "{\"sessionId\":\"166cee263...
     [JSONWP Proxy] Replacing sessionId 166cee263fc8757cbcb5576a52f7229e with 82b9d81c-f725-473d-8d55-ddbc1f92c100
     [HTTP] <-- GET /wd/hub/session/82b9d81c-f725-473d-8d55-ddbc1f92c100/source 200 8 ms - 220 

    如果要替换chromedriver的版本,可以从Appium上输出的Log信息找到chromedriver的路径,在终端依次执行如下命令打开chromedriver所在的文件夹。

    cd /Applications/Appium.app/Contents/Resources/node_modules/appium/node_modules/appium-android-driver/node_modules/appium-chromedriver/chromedriver/mac/
    
    open .

    相应的chromedriver和Chrome版本对应信息和下载地址可以参考:

    selenium之 chromedriver与chrome版本映射表

    5)程序使用的JAR包

    自动化脚本程序要跑起来需要两个压缩包,java-client-3.1.0.jar 和 selenium-server-standalone-2.44.0.jar ,试过使用这两个JAR包的最新版本,会有一些奇奇怪怪的问题,这两个版本的JAR包够用了。

    java-client-3.1.0.jar 可以从Appium官网下载:

    http://appium.io/downloads.html

    selenium-server-standalone-2.44.0.jar 可以从selenium官网下载:

    http://selenium-release.storage.googleapis.com/index.html

    6)虚拟机

    我这边使用的是网易MuMu虚拟机,基于Android 4.4.4平台,在我自己的Mac上跑着没问题,同一个版本安装到公司的Mac上就跑不起来,一打开就崩。后面虚拟机自动升级到了Android6.0.1,脚本跑了就有异常,而且每次打开的时候经常卡死在加载页面,system so库报异常。所以最好还是基于Android4.X的版本上运行脚本,Mac上没有一个通用稳定的虚拟机,自己下几个看看是否能用,个人测试各类型的虚拟机结果如下:

    1)网易MuMu:在Mac上还是比较好用的,但是最新的版本是6.0.1,初始化经常卡死,无法回退到4.4.4平台版本,脚本在Android6.0平台上切换到WebView的上下文环境异常,升级ChromeDriver版本和Appium版本也无法解决此问题。

    2)GenyMotion:微信安装之后无法打开,一直闪退,页面滑动在Mac上巨难操作。

    3)天天模拟器:下载的DMG安装文件根本无法打开。

    4)夜神模拟器:还是比较好用的,但是Appium adb无法连上虚拟机,从Log来看一直在重启adb, 最后程序中断。

    5)逍遥安卓:没有Mac版本。

    6)BlueStack:无法安装,安装过程中异常退出,多次重试还是一样。

    综上,如果是在Mac上运行虚拟机,目前测试有效的是网易MuMu 基于Android 4.4.4 平台的版本,其他版本和虚拟机都有各种问题。

    另:附上Android WebView 历史版本下载地址(需要翻墙):

    https://cn.apkhere.com/app/com.google.android.webview  

    WebView 和对应的ChromeDriver版本见Appium GitHub chromedriver说明文档:

    https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/web/chromedriver.md 

    7)编译IDE

    不做Android开发的可以下载Eclipse IDE,在Eclipse下运行Java程序还比较方便,拷贝工程源码中的三份文件即可

    java-client-3.1.0.jar 
    
    selenium-server-standalone-2.44.0.jar  
    
    AppiumWeChatAuto/appiumauto/src/main/java/com/example/AppiumAutoScan.java 

    Eclipse IDE下载地址:

    http://www.eclipse.org/downloads/packages/

    Java版本和对应的Eclipse IDE版本参考:

    http://wiki.eclipse.org/Eclipse/Installation

    8)GitHub工程源码

    实现源码GitHub地址:

    https://github.com/wenguan0927/AppiumWeChatAuto

    运行Android工程查看设备信息的时候Edit Configurations切换到app,运行自动化脚本的时候切换到AppiumAutoScan。支持按最近一周,一个月,一年或爬取所有历史文章,checkTimeLimit()传入不同限制时间类型的参数即可。

    四、参考资料

    Appium 官方文档

    Appium 常用API

    Appium自动化测试–使用Chrome调试模式获取App混合应用H5界面元素

    Appium 微信 webview 的自动化技术

    Appium Girls 学习手册

    Appium:轻松玩转app+webview混合应用自动化测试

    Appium 微信小程序,driver.context (“WEBVIEW_com.tencent.mm:tools”) 切换 webview 报错

    Appium 事件监听

    妙用AccessibilityService黑科技实现微信自动加好友拉人进群聊

    Appium自动化测试Android

    Windows下部署Appium教程(Android App自动化测试框架搭建)

    微信、手Q、Qzone之x5内核inspect调试解决方案

    selenium之 chromedriver与chrome版本映射表

    (Android开发自测)在Mac OS 10.12 上安装配置appium

    辅助功能 AccessibilityService笔记

    原文链接:https://github.com/wenguan0927/AppiumWeChatAuto

     

    展开全文
  • java实现微信公众号源码 AppiumWeChatAuto 1、如果要实现微信公众号文章的自动采集就必须实现微信公众号文章的自动浏览操作; 2、此工程是基于Appium和Java来实现的Android微信客户端自动化浏览的操作,基于微信...
  • 由于微信公众号爬虫的特殊性,微信公众号爬虫始终是爬虫工程师比较头疼的一个问题。 本文主要介绍一下目前市面上各种爬虫的优劣性以及适用群体 如果您有任何不同见解,或者除文中四种方式之外的方式.欢迎留言跟我...

    文中四种方式,均为我本人亲身使用过, 文中所有的文字及图片均为本人身亲自编写和截图, 如果转载,请标明来源

    由于微信公众号爬虫的特殊性,微信公众号爬虫始终是爬虫工程师比较头疼的一个问题。

    本文主要介绍一下目前市面上各种爬虫的优劣性以及适用群体

    如果您有任何不同见解,或者除文中四种方式之外的方式.欢迎留言跟我交流.

     

    1.搜狗微信(https://weixin.sogou.com/)

    优点: 易于抓取,唯一的限制只有验证码(可以通过更换代理ip避免)

    缺点: 无法通过公众号搜索,获取指定公众号文章, 无法获取永久链接 (文章只有几个小时有效期,过后无法打开),无法获取阅读数

    难点:  验证码(通过代理ip可以解决)

    适用群体: 个人抓取文章后保存,后可用于做数据分析

    原理简介: 通过程序请求搜狗的首页, 分析html结构, 通过正则匹配 拿到文章的url 即可. 如下图所示

    搜狗微信

    2. 基于中间人以及脚本的方式

    优点: 可以低成本获取数据,并且可以获取阅读数

    缺点: 抓取数据有限(微信限制,无法解决),难于部署(需要脚本+抓包工具转发),可能会封号!!!

    适用群体: 个人抓取规模很小的情况下,或者企业用于小规模抓取(100个公众号左右)

    原理简介:

    通过点击的方式 正常向微信发送请求,但是在配置了抓包工具等方式的中间人代理,可以捕获到点击的链接,从而抓取返回的数据发送到服务端

    脚本可以通过按键精灵或者其他语言的自动化程序来实现

    流程演示如下( 演示 使用的是mac版客户端,  win/mac/ios/android 客户端同理 ) 

    a.配置好抓包工具(charles/fiddler) 或中间人代理

    b.在客户端随意点击一篇文章

    配置好抓包工具后点击文章

    c.查看抓包工具的请求

     

    抓到的json数据

    d.配置转发

     

     charles配置转发的方式

    不过这个方式只能转发参数, 转发参数后,可以在服务端模拟请求即可. 后面我会完善一篇anyproxy实现结果的转发.

    不过请注意!!!! 这种方式应该很可能会封号, 因为在点击文章的同时 相当于阅读了某一篇文章. 所以建议拉长抓取间隔,降低每天抓取次数(100~200次之内可能比较合理).

     

    3.公众号后台抓取

    优点: 可以请求多次,并且不依赖与微信号不会有封号的风险

    缺点: 无法抓取阅读数, 需要申请微信公众号, 需要人为操作(授权扫码), 稳定性可能相对差一些(异常导致操作失效)

    难点: 自动化操作流程

    适用群体: 只想抓文章,不需要阅读数,并且对稳定性不太在意的

    原理简介:

    a.首先打开微信公众平台官网 https://mp.weixin.qq.com/ ,并且扫码登录

    b. 左侧菜单栏选择创作管理->图文素材->新的创作->图文消息

     

    c. 点击超链接 选择公众号, 手动输入需要抓取的公众号 

    d.此时可以打开浏览器检查元素 查看一下请求(提前打开检察元素 不然无法拦截到请求)

    可以看到两个 XHR的资源 searchbiz是查询公众号 appmsg是获取公众号文章 

    https://mp.weixin.qq.com/cgi-bin/searchbiz

    https://mp.weixin.qq.com/cgi-bin/appmsg

    具体参数请自行抓包查看 很简单的几个参数

    e.到此为止 整套流程就完事了, 需要做的就是 通过自动化的程序 来实现如下操作, 如果追求一体化的操作并且熟悉python的朋友 可以尝试用selenium来操作,这个方式相对简单一些,如果不太熟悉python的朋友 可以手动登录并且扫码后 导出 cookie , 然后再用自己熟悉的语言,使用cookie并请求接口 即可实现 (核心问题就是cookie) 

     

    4.购买成熟的api方案

    优点: 不需要任何部署,直接调用api即可实现,可获取阅读数和文章,也可以通过关键词搜索

    缺点: 大部分可能需要付费.

    难点: 无

    适用群体: 需求量比较大的企业,并且需要数据稳定性较高

    原理简介:  封装好的数据接口,底层应该是由一套分布式的稳定架构来实现, 由一些小号以及代理ip来实现规模大一点的抓取

    展开全文
  • 微信公众号爬虫.rar

    2019-12-20 16:30:58
    微信公众号完成爬虫,内附整个项目的详细教程和所需相关配置软件,按照教程简单配置即可使用该项目为python的项目,新手小白也可轻松使用
  • 在网站搜索微信公众号爬虫,大多是Python写的,经过几个研究,我用c++也写了基本功能! 爬几千条后会显示访问频繁,接下来将通过代理IP来测试 !有共同的爱好欢迎一起讨论! 交流群 1503118521005923608。 ...
  • 基于Python的微信公众号爬虫 Python是一种解释性的,高级的通用编程语言。 由Guido van Rossum创建并于1991年首次发布,Python的设计理念强调代码可读性,其显着使用了重要的空白。 它的语言结构和面向对象的方法...
  • Python爬虫五:微信公众号爬虫-2018.9

    万次阅读 多人点赞 2018-09-08 23:26:19
    ---全部文章: 京东爬虫 、链家爬虫、美团爬虫、微信公众号爬虫、字体反爬、Django笔记、阿里云部署、vi\vim入门---- 分析:关于微信公众号的爬取,网上搜索了一下,主要有几种方法: 一、搜狗微信公众平台 ...
  • 微信公众号爬虫项目

    千次阅读 2018-10-07 16:38:38
    项目地址:...项目介绍:基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫 项目截图: 欢迎关注我的公众号:【菜鸟要飞】 ,面试宝典、学习路线、源码分享等等你来学 ...
  • 一次微信公众号爬虫

    2019-10-10 18:18:34
    相信大家最近做微信公众号爬虫肯定遇到了很多的问题,其中最大的就是网上很多方法已经不能用了,比如搜狗微信网页端都不能用了,不得不感慨小龙大佬在这方面还是控制的很严的。毕竟现在数据这么值钱,哪能随便就被你...
  • hello,小伙伴们,大家好,今天给大家分享的开源项目是微信公众号爬虫,感兴趣的朋友可以参考一下这个开源项目,看看是否可以给你提供一个新的思路。 项目简介 基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成...
  • 高效微信爬虫,微信公众号爬虫,公众号历史文章,文章评论,文章阅读及在看数据更新,可视化网页,可部署于Windows服务器。 使用环境 基于Python3 ==> flask/mysql/redis/mitmproxy/pywin32等实现 查看及安装依赖...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,307
精华内容 522
关键字:

微信公众号爬虫

爬虫 订阅