动态加载网站的数据爬取 列子:有道翻译 百度翻译破解案列 民政网站数据抓取 多线程爬虫

动态加载网站数据抓取

1、F12打开控制台,页面动作抓取网络数据包
2、抓取json文件URL地址
# 控制台中 XHR :异步加载的数据包
# XHR -> Query String Parameters(查询参数)

有道翻译流程梳理

1. 打开首页
2. 准备抓包: F12开启控制台
3. 寻找地址
   页面中输入翻译单词,控制台中抓取到网络数据包,查找并分析返回翻译数据的地址
4. 发现规律
   找到返回具体数据的地址,在页面中多输入几个单词,找到对应URL地址,分析对比 Network - All(或者XHR) - Form Data,发现对应的规律
5. 寻找JS文件
   右上角 ... -> Search -> 搜索关键字 -> 单击 -> 跳转到Sources,左下角格式化符号{}
6、查看JS代码
   搜索关键字,找到相关加密方法,分析并用python实现(console可调式JS代码)
7、断点调试
8、完善程序

cookie模拟登陆

1、适用网站类型: 爬取网站页面时需要登录后才能访问,否则获取不到页面的实际响应数据
2、方法1(利用cookie)
   1、先登录成功1,获取到携带登陆信息的Cookie(处理headers) 
   2、利用处理的headers向URL地址发请求
3、方法2(利用session会话保持)
   1、登陆,找到POST地址: form -> action对应地址
   2、定义字典,创建session实例发送请求
      # 字典key :<input>标签中name的值(email,password)
      # post_data = {'email':'','password':''}

cookie模拟登录

  • 适用网站及场景
抓取需要登录才能访问的页面
  • 方法一
1、先登录成功1,获取到携带登陆信息的Cookie
   F12打开控制台,在页面输入用户名、密码,登录成功,找到/home(一般在抓到地址的上面)
2、携带着cookie发请求(人人网只检查了Cookie,有道全部检查)
   ** Cookie
   ** Referer(,代表你从哪里转过来的)
   ** User-Agent

  • 方法二
  1. 知识点
利用requests模块中的session会话保持功能
  1. session会话使用流程
1、实例化session对象
   session = requests.session()
2、让session对象发送get或者post请求
   res = session.get(url,headers=headers)
  1. 具体步骤
1、寻找登录时POST的地址
   查看网页源码,查看form,找action对应的地址: http://www.renren.com/PLogin.do

2、发送用户名和密码信息到POST的地址
   * 用户名和密码信息以什么方式发送? -- 字典
     键 :<input>标签中name的值(email,password)
     值 :真实的用户名和密码
     post_data = {'email':'','password':''}
  1. 程序实现
整体思路
1、先POST: 把用户名和密码信息POST到某个地址中
2、再GET:  正常请求去获取页面信息

百度翻译破解案例

目标

破解百度翻译接口,抓取翻译结果数据

实现步骤

  • 1、F12抓包,找到json的地址,观察Form表单数据

    1、POST地址: https://fanyi.baidu.com/v2transapi
    2、Form表单数据(多次抓取在变的字段)
       from: zh
       to: en
       sign: 54706.276099  #这个是如何生成的?
       token: a927248ae7146c842bb4a94457ca35ee 
        # 基本固定,但不同浏览器不一样,想办法获取
    
  • 2、抓取相关JS文件

    右上角 - 搜索 - sign: - 找到具体JS文件(index_c8a141d.js) - 格式化输出
    

3、在JS中寻找sign的生成代码

1、在格式化输出的JS代码中搜索: sign: 找到如下JS代码:sign: m(a),
2、通过设置断点,找到m(a)函数的位置,即生成sign的具体函数
   # 1. a 为要翻译的单词
   # 2. 鼠标移动到 m(a) 位置处,点击可进入具体m(a)函数代码块

4、生成sign的m(a)函数具体代码如下(在一个大的define中)

function a(r) {
        if (Array.isArray(r)) {
            for (var o = 0, t = Array(r.length); o < r.length; o++)
                t[o] = r[o];
            return t
        }
        return Array.from(r)
    }
function n(r, o) {
    for (var t = 0; t < o.length - 2; t += 3) {
        var a = o.charAt(t + 2);
        a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),
            a = "+" === o.charAt(t + 1) ? r >>> a : r << a,
            r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a
    }
    return r
}
function e(r) {
    var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
    if (null === o) {
        var t = r.length;
        t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))
    } else {
        for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)
            "" !== e[C] && f.push.apply(f, a(e[C].split(""))),
                C !== h - 1 && f.push(o[C]);
        var g = f.length;
        g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))
    }
//运行时报错:window....,分析页面源码,断点调试,找到了
//u的值其实就是页面源码中 window.gtk 的值
//    var u = void 0
//    , l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
//    u = null !== i ? i : (i = window[l] || "") || "";   
    var u = '320305.131321201'
    
    for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
        var A = r.charCodeAt(v);
        128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),
            S[c++] = A >> 18 | 240,
            S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,
                                                                    S[c++] = A >> 6 & 63 | 128),
                                S[c++] = 63 & A | 128)
    }
    for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)
        p += S[b],
            p = n(p, F);
    return p = n(p, D),
        p ^= s,
        0 > p && (p = (2147483647 & p) + 2147483648),
        p %= 1e6,
        p.toString() + "." + (p ^ m)
}
var i = null;
//此行报错,直接注释掉即可
//t.exports = e
  • 5、直接将代码写入本地js文件,利用pyexecjs模块执行js代码进行调试

    1、安装pyexecjs
       sudo pip3 install pyexecjs
    2、安装js执行环境:nodejs
       sudo apt-get install nodejs
    # 执行js代码流程
    import execjs
    with open('node.js','r') as f:
        js_data = f.read()
    execjs_obj = execjs.compile(js_data)
    sign = execjs_obj.eval('e("tiger")')
    
  • 获取token

    # 在js中
    token: window.common.token
    # 在响应内容中想办法获取此值
    # url地址为百度翻译的首页,响应中会有token
    url = 'https://fanyi.baidu.com/?aldtype=16047'
    正则表达式: "token: '(.*?)'"
    
  • 具体代码实现

    
    

民政部网站数据抓取

目标

1、URL: http://www.mca.gov.cn/ - 民政数据 - 行政区划代码
   即: http://www.mca.gov.cn/article/sj/xzqh/2019/
2、目标: 抓取最新中华人民共和国县以上行政区划代码

实现步骤

  • 1、从民政数据网站中提取最新行政区划代码
# 特点
1、最新的在上面
2、命名格式: 2019年X月中华人民共和国县以上行政区划代码
  • 2、从二级页面链接中提取真实链接(反爬-响应内容中嵌入JS,指向新的链接)

    1、向二级页面链接发请求得到响应内容,并查看嵌入的JS代码
    2、正则提取真实的二级页面链接
    
  • 3、在数据库表中查询此条链接是否已经爬取,建立增量爬虫

    1、数据库中建立version表,存储爬取的链接
    2、每次执行程序和version表中记录核对,查看是否已经爬取过
    
  • 4、代码实现

    
    

多线程爬虫

应用场景

1、多进程 :CPU密集程序
2、多线程 :爬虫(网络I/O)、本地磁盘I/O

lock = Lock()
n = 5000

def f1():
    for i in range(2000):
        lock.acquire()
        n = n + 1
        lock.release()

def f2():
    for i in range(2000):
        lock.acquire()
        n = n - 1
        lock.release()

t1 = Thread(target=f1)
t1.start()
t2 = Thread(target=f2)
t2.start()

# x = n + 1  x=5001,n=5000
# x = n - 1  n=5000,x=4999  
# n = x      n=4999
# n = x      n=4999

  • 队列
# 导入模块
from queue import Queue
from multiprocessing import Queue
# 使用
q = Queue()
q.put(url)
q.get() # 当队列为空时,阻塞
q.empty() # 判断队列是否为空,True/False
  • 线程模块
# 导入模块
from threading import Thread

# 使用流程  
t = Thread(target=函数名) # 创建线程对象
t.start() # 创建并启动线程
t.join()  # 阻塞等待回收线程

# 如何创建多线程,如下方法你觉得怎么样?????
t_list = []

for i in range(5):
    t = Thread(target=函数名)
    t_list.append(t)
    t.start()
    
for i in t_list:
    i.join()

小米应用商店抓取(多线程)

  • 目标
1、网址 :百度搜 - 小米应用商店,进入官网
2、目标 :应用分类 - 聊天社交
   应用名称
   应用链接
  • 实现步骤
  1. 确认是否为动态加载
1、页面局部刷新
2、右键查看网页源代码,搜索关键字未搜到
# 此网站为动态加载网站,需要抓取网络数据包分析
  1. F12抓取网络数据包
1、抓取返回json数据的URL地址(Headers中的Request URL)
   http://app.mi.com/categotyAllListApi?page={}&categoryId=2&pageSize=30
        
2、查看并分析查询参数(headers中的Query String Parameters)
   page: 1
   categoryId: 2
   pageSize: 30
   # 只有page在变,0 1 2 3 ... ... ,这样我们就可以通过控制page的值拼接多个返回json数据的URL地址
  • 代码实现

json解析模块

json.loads(json格式字符串)

  • 作用
把json格式的字符串转为Python数据类型
  • 示例
html_json = json.loads(res.text)

json.dump(python,f,ensure_ascii=False)

  • 作用
把python数据类型 转为 json格式的字符串
# 一般让你把抓取的数据保存为json文件时使用
  • 参数说明
1个参数: python类型的数据(字典,列表等)2个参数: 文件对象
第3个参数: ensure_ascii=False # 序列化时编码
  • 示例
import json

app_dict = {
    '应用名称' : 'QQ',
    '应用链接' : 'http://qq.com'
}
with open('小米.json','a') as f:
	json.dump(app_dict,f,ensure_ascii=False)

相关复习

1、小米应用商店
2、有道翻译案例复写一遍
3、百度翻译案例复写一遍
4、民政部数据抓取案例完善
   # 1、将抓取的数据存入数据库,最好分表按照层级关系去存
   # 2、增量爬取时表中数据也要更新
5、把链家二手房案例改写为多线程
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值