爬虫能不能爬到微信怎么查一个人在群里的所有聊天记录?

背景:某一天,拿着自己的手机看着技术文章,然而手机看技术文章,有时候确实蛋疼,因为一旦代码多起来,小屏幕看的还是眼花;又或者某一天觉得这一篇文章,觉得写的很棒棒哦,于是先收藏,打算过几天看,然后等我几天再次打开收藏的文章,卧X,居然被作者删了···;或者想对某个博主的文章进行分类··· 于是就萌生了能不能爬下“微信公众号”文章,保存到电脑的想法 如今普天盖地的安利 Python ,虽然有着“人生苦短,我用 Python”一说,但我还是想在「爬虫」这方面支持一下我大 Java (好吧,其实自己折腾一番,还是写着
Java
舒服,平时写
python
还是少) 一、抓包关于手机抓包(这里指 Android 手机),推荐使用 Fiddler 工具来抓包,Fiddler 自行去下载。划重点:请确保电脑和手机连接在同一局域网的同一个 WiFi,别又说怎么抓不到包1.查询电脑当前 IPWin + R (快捷键),打开【运行】窗口,然后输入 cmd 回车,弹窗命令窗口,紧接着输入:ipconfig 记着 ip,一会配置手机 WiFi,不会配置的可以看 Fiddler 官网这篇文章: docs.telerik.com/fiddler/Con… 打开手机 WiFi 管理,显示 WiFi 的高级选项,设置代理服务器为手工,代理主机名为刚刚电脑 IPv4 地址:192.168.0.XXX ,代理服务器端口默认设置为:88882.手机安装 Fiddler 证书 因为微信的网络请求为 HTTPS ,安全性高,所以 Fiddler 需要在手机端安装它的信任证书,才能抓到微信的请求( 比喻:Fiddler 充当代理人、中间商,在建立 https 的过程搞事情,瞒天过海,以获取信任 )。 操作如下: 手机浏览器打开:ipv4.fiddler:8888/
下载证书 FiddlerRoot Certificate
手机安装这个证书,安装过程可能需要设置屏幕密码
打开 【Fiddler】-【Tools】-【HTTPS】,勾选 Capture HTTPS traffic
二、爬虫配置好抓包 工具 之后,打开某公众号,切换历史文章消息,然后点击更多消息,此时观察 Fiddler 抓包情况。每次抓包前,建议先清空历史抓包数据,然后在执行操作,这样方便定位链接。于是我们可以很轻易的拿到微信公众号获取文章接口地址: mp.weixin.qq.com/mp/profile_…
切换到 WebForms 选项卡,可以看到 Get 请求下的参数信息,后面我们模拟请求,照着写就 ok 了( Get 请求参数,可以写在链接里面) 在上面这个图,我框了几个重要参数的,这几个参数涉及到微信服务端的校验相关操作,所以在复制的时候,记得不要搞错了,否则会提示 session 错误。 我个人试错发现,每次爬一个新的公众号,只需对应修改这 4 个参数即可: __biz、appmsg_token、pass_ticket、wap_sid2
如何爬取所有文章呢?做过手机客户端的童鞋,应该知道我们用 Recyclerview 或 ListView 做 下拉刷新或者上拉加载更多 的时候,接口一般需要配置 nextpage 的参数吧,对应微信文章接口就是: offset 参数(理解为偏移量), count 参数(理解为每次加载的数目)。
举例:我设置 offset 为0, count 为 10,那么第一页数据就加载10条,那第二页的起始点就应该是 offset = 10 , count 不作修改依旧为 10。希望大家能理解我的例子,相信这个不难 1.构建请求,递归调用请求这东西,当然是 okhttp 来啦,引用相关 jar 包或者 gradle 依赖。说明一下:User-Agent 使用 Fiddler 抓取的值,以模拟手机客户端的请求。核心代码如下:String url = "https://mp.weixin.qq.com/mp/profile_ext?action=getmsg&__biz=%s&f=json&offset=%d&count=10&is_ok=1&scene=126&uin=777&key=777&pass_ticket=%s&wxtoken=&appmsg_token=%s&f=json ";
url = String.format(url, MyClass.__biz, startIndex, MyClass.pass_ticket, MyClass.appmsg_token);
//
System.out.println(url);
String cookie = "rewardsn=; wxtokenkey=777; wxuin=777750088; devicetype=android-26; version=2700033c; lang=zh_CN; pass_ticket=%s; wap_sid2=%s";
cookie = String.format(cookie, MyClass.pass_ticket, MyClass.wap_sid2);
Request request = new Request.Builder()
.url(url)
.get()
.addHeader("Host", "mp.weixin.qq.com")
.addHeader("Connection", "keep-alive")
.addHeader("User-Agent", "Mozilla/5.0 (Linux; Android 8.0.0; SM-G9500 Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/044704 Mobile Safari/537.36 MMWEBID/8994 MicroMessenger/7.0.3.1400(0x2700033C) Process/toolsmp NetType/WIFI Language/zh_CN")
.addHeader("Accept-Language", "zh-CN,zh-CN;q=0.9,en-US;q=0.8")
.addHeader("X-Requested-With", "XMLHttpRequest")
.addHeader("Cookie", cookie)
.addHeader("Accept", "*/*")
.build();
Response response = okHttpClient.newCall(request).execute();
if (response.isSuccessful()) {
String body = response.body().string();
JSONObject jo = new JSONObject(body);
if (jo.getInt("ret") == 0) {
currentTimes++;
System.out.println("当前是第" + currentTimes + "次");
String general_msg_list = jo.getString("general_msg_list");
general_msg_list = general_msg_list.replace("\\/", "/");
// json 解析
JSONObject jo2 = new JSONObject(general_msg_list);
JSONArray msgList = jo2.getJSONArray("list");
for (int i = 0; i < msgList.length(); i++) {
JSONObject j = msgList.getJSONObject(i);
JSONObject msgInfo = j.getJSONObject("comm_msg_info");
long datetime = msgInfo.getLong("datetime");
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String date = sdf.format(new Date(datetime * 1000));
if (j.has("app_msg_ext_info")) {
JSONObject app_msg_ext_info = j.getJSONObject("app_msg_ext_info");
JSONArray multi_app_msg_item_list = app_msg_ext_info.getJSONArray("multi_app_msg_item_list");
if (multi_app_msg_item_list.length() > 0) {
//多图文 do nothing
} else {
String content_url = app_msg_ext_info.getString("content_url");
String title = app_msg_ext_info.getString("title");
int copyright_stat = app_msg_ext_info.getInt("copyright_stat");
String record = date + "-@@-" + title + "-@@-" + content_url;
System.out.println(record);
datas.add(record);
}
} else {
System.out.println("非图文推送");
}
}
// can_msg_continue 来判断是否还有下一页数据
if (jo.getInt("can_msg_continue") == 1) {
Thread.sleep(1000);
startIndex = jo.getInt("next_offset");
execute();
} else {
System.out.println("爬取完成!");
// 完成之后,保存结果
saveToFile();
}
} else {
System.out.println("无法获取文章,参数错误");
}
}
复制代码2.保存文章信息 好像代码也不是特别多,哈哈,然后把爬取的数据保存到一个 txt 文本文件里面,我这边用的格式是: 时间-@@-标题-@@-链接 ( 后面方便使用“-@@-”分割字符串 ),当然你也可以连接 Mysql,来存储信息,我就偷懒了,没搞了。 三、Html 转 Pdf 既然拿到每一篇文章的 Url 了,那保存成 Html 不是很 easy 的事情吗,但是如何将 html convert Pdf 呢? 1.wkhtmltopdf 工具1.1下载 wkhtmltopdf 并安装 传送门:wkhtmltopdf.org/,注意:系统版本的选择,我这边是 Windows 系统 1.2配置环境变量如果你没有配置系统环境变量的话,就需要到 wkhtmltopdf 的安装目录下的 bin 文件夹下面,去执行命令1.3如何使用例如:你想把 Google 网页转成 pdfwkhtmltopdf http://google.com google.pdf
复制代码2.解决 wkhtmltopdf 保存图片丢失问题 通过 wkhtmltopdf 保存 pdf 的时候,存在网络图片丢失的问题,也就是不显示图片,那如何解决这个问题呢? 通过替换 html 中,img 标签的 data-src 和 src 的属性值,由 http 链接改为本地路径即可 。
思路:请求文章 url ,获取 html 信息,通过 jsoup 解析 html,然后通过选择器选择 img 标签,接着获取 img 的 data-src 的属性值(图片地址),然后遍历下载图片到本地,下载图片成功之后,通过 jsoup 提供的方法,修改该 img 的 data-src 的属性值,替换原先的 html 信息。核心代码如下: Jsoup介绍:html解析神器Request request = new Request.Builder().url(url).get().build();
Response response = okHttpClient.newCall(request).execute();
if (response.isSuccessful()) {
String html = response.body().string();
//
System.out.println(html);
Document doc = Jsoup.parse(html);
//找到图片标签
Elements img = doc.select("img");
for (int i = 0; i < img.size(); i++) {
// 图片地址
String imgUrl = img.get(i).attr("data-src");
if (imgUrl != null && !imgUrl.equals("")) {
Request request2 = new Request.Builder()
.url(imgUrl)
.get()
.build();
Response execute = okHttpClient.newCall(request2).execute();
if (execute.isSuccessful()) {
String imgPath = imgDir + MD5Utils.MD5Encode(imgUrl, "") + ".png";
File imgFile = new File(imgPath);
if (!imgFile.exists()) {
// 下载图片
InputStream in = execute.body().byteStream();
FileOutputStream ot = new FileOutputStream(new File(imgPath));
BufferedOutputStream bos = new BufferedOutputStream(ot);
byte[] buf = new byte[8 * 1024];
int b;
while ((b = in.read(buf, 0, buf.length)) != -1) {
bos.write(buf, 0, b);
bos.flush();
}
bos.close();
ot.close();
in.close();
}
//重新赋值为本地路径
img.get(i).attr("data-src", imgPath);
img.get(i).attr("src", imgPath);
//导出 html
html = doc.outerHtml();
}
execute.close();
}
}
String htmlPath = dirPath + fileName + ".html";
final File f = new File(htmlPath);
if (!f.exists()) {
Writer writer = new FileWriter(f);
BufferedWriter bw = new BufferedWriter(writer);
bw.write(html);
bw.close();
writer.close();
}
// 转换
HtmlToPdf.convert(htmlPath, destPath);
// 删除html文件
if (f.exists()) {
f.delete();
}
response.close();
}
复制代码3.转换成 PDF/**
* html转pdf
*/
public static boolean convert(String srcPath, String destPath) {
StringBuilder cmd = new StringBuilder();
cmd.append("wkhtmltopdf");
cmd.append(" ");
cmd.append("--enable-plugins");
cmd.append(" ");
cmd.append("--enable-forms");
cmd.append(" ");
cmd.append(" \"");
cmd.append(srcPath);
cmd.append("\" ");
cmd.append(" ");
cmd.append(destPath);
System.out.println(cmd.toString());
boolean result = true;
try {
Process proc = Runtime.getRuntime().exec(cmd.toString());
HtmlToPdfInterceptor error = new HtmlToPdfInterceptor(proc.getErrorStream());
HtmlToPdfInterceptor output = new HtmlToPdfInterceptor(proc.getInputStream());
error.start();
output.start();
proc.waitFor();
} catch (Exception e) {
result = false;
e.printStackTrace();
}
return result;
}
复制代码 获取终端输入输出信息,上面代码的 HtmlToPdfInterceptor public class HtmlToPdfInterceptor extends Thread {
private InputStream is;
public HtmlToPdfInterceptor(InputStream is) {
this.is = is;
}
@Override
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is, "utf-8");
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line.toString()); //输出内容
}
} catch (IOException e) {
e.printStackTrace();
}
}
复制代码wkhtmltopdf 的转换过程速度比较慢,建议开多个线程搞,我是 5 个线程去转换,最后看一下成果图(python 党别喷代码量哈,求放过~)小结感谢您的阅读,如有不对的地方,还请指出修正!文中不理解的地方,可加 qq 交流:1029226002。

本期推送整理了初学者可能会用到的Python资料,含有书籍/视频/在线文档和编辑器/源代码,关于Python的安装qun:850973621
1. 场景经常有小伙伴在交流群问我,每天的早报新闻是怎么获取的?其实,早期使用的方案,是利用爬虫获取到一些新闻网站的标题,然后做了一些简单的数据清洗,最后利用 itchat 发送到指定的社群中。由于爬虫面对 网站改版的不稳定性及 itchat 不安全性,所以放弃了这种方案后期更改了一种方案,通过修改爬虫方案,创建 API 服务,编写 App 去获取数据,然后手动发送到微信群本篇文章将和大家详细聊聊具体的实现过程2. 数据爬取第 1 步,通过 Python 爬虫获取数据获取方式有 2 种,分别是:已有的新闻早报网站、新闻网站的头条新闻选择一种爬虫方式,就能很快地爬取到目标网站的数据第 2 步,数据清洗,排序将爬取到的数据先进行一次关键字筛选,然后按照点赞或者阅读数按照热点进行排序第 3 步,参数化,去重去掉数据中重复的新闻,然后将最后展示的数目参数化# 按照点赞数目,降序排列
news_sorted_pro = sorted(news, key=itemgetter('news_approve_num'), reverse=True)
result = []
for news_sorted_item in news_sorted_pro:
result.append(news_sorted_item.get('title'))
# 去重
result = sorted(set(result), key=result.index)
# 只取前12条数据
result = result[:self.news_num] if len(result) >= self.news_num else result
复制代码
需要注意的是,由于新闻网站会经常改版,建议爬取多个新闻网站,做好异常处理,做一个优先级,如果一个网站爬取数据失败,切换到下一个级别的网站爬取数据3. 服务化将数据服务化,即编写 API,目的是为了方便终端调用如果使用 Python 编写 API,建议使用 FastAPI 或 Flask 框架,因为这两个框架开发 API 方便快捷,以 FastAPI 为例:第 1 步,安装依赖包含 FastAPI 框架及 hypercorn 依赖,hypercorn 是独立的 ASGI 服务器,方便 FastAPI 项目的部署# FastAPI框架
pip3 install fastapi
pip3 install hypercorn
复制代码
第 2 步,编写 API使用 FastAPI 很方便,不到 10 行代码就能编写一个接口服务只需要实例化 FastAPI 对象,利用装饰器指定请求方法和路径即可,调用上面的爬虫方法即可。from fastapi import FastAPI
# 实例化
app = FastAPI()
# API,Get方式
@app.get("/last_news")
def get_last_news():
"""
最新的新闻
:return:
"""
news = get_news()
data = {
'code': 0,
'news': news
}
# 封装
return data
复制代码
如要想本地调试 API,可以通过 uvicorn 命令运行项目# 运行项目
uvicorn news:app --reload
复制代码
然后访问下面的地址,查看返回的新闻数据http://127.0.0.1:8000/last_news第 3 步,生成依赖迁移文件使用 pip freeze 命令将在本地生成依赖迁移文件# 生成迁移文件
pip freeze > requirements.txt
复制代码
第 4 步,上传代码将代码上传到代码托管平台,比如:码云、GitLab 等第 5 步,服务器拉取代码服务器中通过 git 拉取代码,并通过依赖文件一键安装所有依赖# 安装依赖
pip3 install -r requirements.txt
复制代码
第 6 步,运行服务使用 hypercorn 运行 FastAPI 项目,使进程一直在后台运行,并保存运行日志信息# 后台运行
# 保存日志,绑定端口号为:8000
# nohup hypercorn news:app --bind 0.0.0.0:8000 > /news.log 2>&1 &
复制代码
需要注意的是,项目绑定的端口号需要在防火墙和云服务器安全组开启当然,如果使用 Java 编写 API,推荐使用 Spring Boot,可以快速开发一个 Restful API 服务4. 编写 App完成 API 服务之后,接下来就是在终端编写一款 App 去访问 API,拿到数据并展示出来以编写一款 Android 应用为例首先,我们在界面上放置一个文本显示框和一个按钮控件然后,对按钮控件设置点击事件的监听get_news_btn = findViewById(R.id.get_news_btn);
//监听事件
get_news_btn.setOnClickListener(this);
@Overridepublic void onClick(View v)
{
switch (v.getId())
{
case R.id.get_news_btn:
news_et.setText("获取中。。。");
getNewsMet();
break;
}
}
复制代码
接着,使用 Android 的网络请求框架 OkHttp 框架调用 API 获取数据/***
* 获取新闻
*/
private void getNewsMet()
{
OkHttpClient okHttpClient = new OkHttpClient();
//构建请求信息:连接请求url 请求方法method 请求头部headers 请求体body 标签tag
Request request = new Request.Builder().url(url).get().build();
//
Call call = okHttpClient.newCall(request);
okHttpClient.newCall(request).enqueue(new Callback()
{
@Override
public void onFailure(Call call, IOException e)
{
Log.d("xag", "获取失败");
showResult(false, "");
}
@Override
public void onResponse(Call call, final Response response) throws IOException
{
Log.d("xag", "获取成功")
parseJsonWithJsonObject(response);
}
}
);}
复制代码
最后,将新闻数据显示在文本控件中,并复制到系统剪切板private void copyToClip(String content)
{
//获取剪贴板管理器:
ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
// 创建普通字符型ClipData
ClipData mClipData = ClipData.newPlainText("Label", content);
// 将ClipData内容放到系统剪贴板里。
if (null != cm)
{
cm.setPrimaryClip(mClipData);
}
}
复制代码
如果只有 iOS 设备,使用 Xcode 编写 iOS 应用,建议将 Xcode 升级到 11.0 以上创建项目的时候,推荐使用 SwiftUI 构建 UI 界面,然后利用 CocoaPods 添加 Alamofire 网络请求依赖库,其他操作步骤和 Android 端类似,这里不展开说明# Uncomment the next line to define a global platform for your project
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!
target 'news_eve' do
# Comment the next line if you don't want to use dynamic frameworks
pod 'Alamofire'
pod 'SwiftyJSON'
pod 'HandyJSON'
# Pods for news_eve
end
复制代码
5. 最后上面步骤只需要点击 App 中的按钮,早报新闻就复制到系统剪切板了,接着可以转发到多个微信群了当然,最后一步也可以利用 SoloPi 或者无障碍,将内容利用自动化操作,一键转发出去作者:Python肖邦链接:https://juejin.cn/post/6902670221334151175来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我要回帖

更多关于 怎么查一个人在群里的所有聊天记录 的文章

 

随机推荐