先上结果:

  之前 在公司业务中用过java+Selenium+ChromeDriver ,使用起来非常顺手,可以完美模拟真实的用户浏览行为。最近休息的时候想用C#也试一下,于是有了本文。

  实现原理一样,只是由java换成了C#。(ps:个人感觉就业务开发代码来说,熟悉之后两种语言可以无缝切换。)

  事先声明,代码中会采集用户登录咕咚网站之后的个人数据接口,如果此行为损害了咕咚网站的利益,请联系我删除或修改本文(我对采集行为一直本着每一次调用之后sleep的原则,毕竟不是为了把人家的网站搞死)。文中使用的数据是我自己的跑步数据,不涉及到其他用户的数据。

  项目结构:为了方便跑友使用,用的winform程序,附nuget包

以下是form1.cs的代码,删除了部分提示的 MessageBox.Show(),从产品角度来讲,应该添加loading提示和进度条,这里就只放代码了。需要安装最新的chrome浏览器+代码中使用的chromedriver是 v2.9.248315

 using Newtonsoft.Json;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms; namespace GuDongLine
{
public partial class Form1 : Form
{
public Form1()
{ InitializeComponent();
label2.Text = "请根据提示进行操作,本产品需要最新版本Chrome浏览器支持,网络良好的情况下运行,内部交流,不作为商业软件,如有侵权请扫中间微信二维码联系我。祝各位跑友生活愉快,身体健康,happy PB";
}
delegate void ChangeInvoke(int num);
public int Fun1;
private void button1_Click(object sender, EventArgs e)
{
try
{
Thread thread = new Thread(go);
thread.Start(); }
catch (Exception)
{
MessageBox.Show("操作异常,请重新打开,或联系我");
} }
private void ChangeNum()
{
MessageBox.Show("正在运行请等待!运行完毕后会有提示!");
}
public void go()
{
if (MessageBox.Show("下面请登录咕咚,本软件只会向咕咚官网发送和接受数据,如果发现软件向其他网址发送数据,说明本软件被修改,可能有病毒", "登录咕咚账号", MessageBoxButtons.OKCancel).Equals(DialogResult.OK))
{
ChromeOptions options = new ChromeOptions();
options.AddArguments("--test-type", "--ignore-certificate-errors");
IWebDriver driver = new ChromeDriver(System.Environment.CurrentDirectory, options);
driver.Url = "http://www.codoon.com/home";
Thread.Sleep(); driver.Navigate().GoToUrl("http://www.codoon.com/gps_sports/my_routes"); Thread.Sleep();
int runCount = int.Parse(driver.FindElement(By.Id("current_index")).Text) / ;
for (int i = ; i < runCount + ; i++)
{
try
{
driver.FindElement(By.ClassName("more_data")).Click();
Thread.Sleep();
}
catch (Exception)
{
if (i > runCount + )
{
break;
} }
}
Thread thread2 = new Thread(ChangeNum);
thread2.Start();
string userId = driver.FindElement(By.ClassName("home_user_header")).GetAttribute("src").Substring(, );
string data = "";
dynamic va = driver.FindElements(By.ClassName("detail_sports_content"));
foreach (IWebElement iwe in va)
{
using (var client = new WebClient())
{
Thread.Sleep();
var responseString = client.DownloadString("http://www.codoon.com/gps_sports/route?user_id=" + userId + "&route_id=" + iwe.FindElement(By.TagName("table")).GetAttribute("id") + "&need_next=1&_=1520349266435"); var DynamicObject = JsonConvert.DeserializeObject<dynamic>(responseString);
string ss = "";
foreach (var s in DynamicObject.line)
{
ss += ((double)s[] + 0.0062).ToString() + "," + ((double)s[] + 0.00135).ToString() + ";";
}
ss = ss.Remove(ss.Length - );
data += ss + "&";
}
}
data = data.Remove(data.Length - );
driver.Close();
string html = @"<!DOCTYPE html><html lang='zh - CN\'>
<head> <meta charset = 'utf-8'> <meta http - equiv = 'X-UA-Compatible' content = 'IE=edge'> <meta name = 'viewport' content = 'width=device-width, initial-scale=1'> <title> my_all_run_lines </title> <link rel = 'stylesheet' href = 'http://cache.amap.com/lbs/static/main1119.css' />
</head>
<body>
<div id = 'container' class='container'></div>
<script src = 'http://webapi.amap.com/loca?key=6ac3f558819c2c4711ea0c0a37192137'></script>
<script src='http://a.amap.com/Loca/static/dist/jquery.min.js'></script>
<script> var map = Loca.create('container', {
key: '1e387d3db027b46a23600cf7f2ed7344',
mapStyle: 'amap://styles/grey',
features: ['bg', 'road'],
zoom: 10
}); var layer = Loca.visualLayer({
container: map,
type: 'line',
shape: 'line',
}); $.get('http://a.amap.com/Loca/static/mock/buslines.txt', function (data) {
data = '" + data + "';" + "" +
"" +
"" +
"" +
"" +
"" + @"var lines = data.split('&').map(function (item) {
return {
linePath: item.split(';').map(function(lnglat) {
return lnglat.split(',');
})
};
}); layer.setData(lines, {
lnglat: 'linePath'
});
layer.setOptions({
style: {
opacity: 0.2,
lineWidth: 2,
stroke: '#b7eff7',
}
}); layer.render();
}) </script>
</body>
</html>"; string path = System.Environment.CurrentDirectory + "\\map.html";
File.WriteAllText(path, html);
}
else
{
System.Environment.Exit();
}
} }
}

  说一下思路:

    1.确定使用的语言和采集框架。

    2.确定数据来源,从咕咚app还是咕咚网站,如果咕咚网站没有提供接口,估计就得去研究app了。本文中耗费时间的一个点就在研究咕咚网站的请求数据的规则上了,原则来说,只要正常用户能打开的网页,无法挡住采集工具。

    3.数据的展示:找了百度地图和高德地图的api接口,两个也都分别试了一下,其实咕咚网本身是使用的谷歌的,但是谷歌的接口研究起来不太方便,最后从数据展示的效果上选择了高德地图,顺便说一下,从咕咚采集的跑步数据其实是一组一组的经纬度坐标,而且是被阉割的经纬度,精确度不够,所以地图上显示的时候会有偏差,随着跑步距离的增长,数据量也比较大,以文中1700公里的跑量,生成的展示html是2.42M ,我家里的古董笔记本加载的时间比较长。

  另:很久以前跟咕咚的客服打过电话,想要一个集成自己所有跑步路线的功能,貌似答应的很好,但是没发现app中有此功能(本文的由来?),当然,如果提供这个功能,一下加载这么多数据,对服务器来说不太好,但是可以迂回一下嘛,比如只生成一个月之前的?申请之后生成?个人感觉有许多解决办法,而且也能做成一种营销活动。

  欢迎探讨,欢迎指教,谢谢大家,希望每一个程序员身体健康。

                                                                    by:跑过16+17北马的coder

    

用C#+Selenium+ChromeDriver 生成我的咕咚跑步路线地图的更多相关文章

  1. ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml) 用javascript在客户端删除某一个cookie键值对 input点击链接另一个页面,各种操作。 C# 往线程里传参数的方法总结 TCP/IP 协议 用C#+Selenium+ChromeDriver 生成我的咕咚跑步路线地图 (转)值得学习百度开源70+项目

    ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml)   我们都知道在使用WebApi的时候Controller会自动将Action的返回值自动进行各种序列化处理(序列化为 ...

  2. selenium + ChromeDriver 实战系列之启信宝(一)

    之前写了一篇selenium + ChromeDriver的一些入门的知识,这篇博客里面找了启信宝这个网站,简单的进行了一个实战练习.本篇博客的结构如下:       首先会给出一些使用seleniu ...

  3. 一次失败的Selenium chromedriver切换

    背景 Selenium webdriver一直使用Firefox作为浏览器来跑webtest, 但是最近发现ff有时会报超时的错误,于是想到使用chromedriver来提升稳定性.本想只把.fire ...

  4. 使用Selenium+ChromeDriver登录微博并且获取cookie

    using OpenQA.Selenium;using OpenQA.Selenium.Chrome; public class GetSinaCookie { private static stri ...

  5. 无界面Ubuntu服务器搭建selenium+chromedriver+VNC运行环境

    搭建背景 有时候我们需要把基于selenium的爬虫放到服务器上跑的时候,就需要这样一套运行环境,其中VNC是虚拟的显示模式,用于排查定位线上问题以及实时运行情况. 搭建流程 安装虚拟输出设备:sud ...

  6. centos7无GUI运行selenium chromedriver 亲测可用!

    1. 安装chrome 首先安装google的epel源 vi /etc/yum.repos.d/google.repo [google] name=Google-x86_64 baseurl=htt ...

  7. scrapy+selenium+chromedriver解析动态渲染页面

    背景:动态页面是页面是通过js代码渲染出来的,无法直接使用scrapy爬虫,这是就需要先把js代码转为静态的html,再用scrapy爬虫就可以解决 解决办法:增加SeleniumMiddleware ...

  8. selenium:chromedriver与chrome版本的对应关系

    转自:http://blog.csdn.NET/huilan_same/article/details/51896672 再使用selenium打开chrome浏览器的时候,需要用chromedriv ...

  9. 19.Selenium+Python生成测试报告

    1.代码如下所示: from selenium import webdriver import unittest import HTMLTestRunner class BaiduSearch(uni ...

随机推荐

  1. 使用 DG Tweening

    在iphone上卡顿的话,使用application.frame更改刷新帧率

  2. MySQL ERROR 1054(42S22)

    修改用户的密码,网上搜到的命令为如下 执行后报错 ERROR 1054(42S22) Unknown column 'password' in ‘field list’ 错误的原因是 5.7版本下的m ...

  3. YARN配置

    环境搭建 mapred-site.xml <configuration> <property> <name>mapreduce.framework.name< ...

  4. ueditor内容带格式回显(html字符串回显)

    简单描述:项目里有个地方用到啦ueditor,用来输入XX描述就用电影film代替,保存后,获取到ueditor里的内容(html字符串),保存到数据库. 吐槽:回显的时候,无论怎么处置,就是死活不好 ...

  5. centos/redhat命令行上传下载文件

    前言:客户端上没有安装xftp,winscp等等软件,无法将服务器上需要的文件下载到本地去解析,无法将本地的安装包上传到服务器上去,这个时候命令行就可以带你翱翔一波 配置如下: 服务器上: 1.安装需 ...

  6. 2018-2019-2 20165328《网络对抗技术》Exp0 Kali安装week1

    1.下载Kaili安装资源并解压安装到虚拟机: 2.修改默认字体与共享文件设置: 3.更新软件源与下载中文输入法: 4.安装完成.

  7. Python 实现整数线性规划:分枝定界法(Branch and Bound)

    今天做作业,要实现整数线性规划的分枝定界法算法.找了一些网上的博客,发现都很屎,感觉自己写的这个比较清楚.规范,所以在此记录.如有错误,请指正. from scipy.optimize import ...

  8. shell 处理小数位加减法(比较)运算

    有一个shell脚本需要处理小数位运算,刚开始使用了expr Java代码   a=7.9 b=10 c=`expr  $a \> $b` 结果运算错误,因为expr只支持整数运算,不支持小数. ...

  9. unity 时间转换方式

    第一种  计时器的写法 带有调用系统时间 using System; using System.Collections; using System.Collections.Generic; using ...

  10. SpringBoot简单入门

    一.创建SpringBoot项目 1.创建maven项目,pom引入springboot父级启动器(starter)依赖: <?xml version="1.0" encod ...