【爬虫】爬取个人随手记账户

 

实现功能:爬取本人随手记账户中的记录,保存到word文档,包括:日期,分类,说的话和图片

具体步骤如下:

 

一、登陆账户

首先要访问随手记,需要登陆才能看到详细记录,之前考虑浏览器填写表单,POST给服务器,但是抓取了几次POST数据后,发现每次POST的密码都进行了某种加密,每次都不一样,如图所示:

没有做过这方面的研究,不知道如何POST,(期待大神指教!),只好作罢,这里利用COOKIE登陆。

def Login(cookie_str):
    
    #浏览器登录后得到的cookie,一定要是Response Header里 status为200 OK的那个数据里的cookie
#    cookie_str = cookie
    #把cookie字符串处理成字典,以便接下来使用
    cookies = {}
    for line in cookie_str.split(';'):
        key, value = line.split('=', 1)
        cookies[key] = value
    
    #设置请求头
    headers = {'User-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'}
    #在发送get请求时带上请求头和cookies
    #resp = requests.get(url, headers = headers, cookies = cookies) 
    #用get方法,得到的实际是https://www.sui.com/tally/new.do的结果,没有需要的数据
    
    resp = requests.get(url,headers = headers, cookies = cookies)

    #检查是否登录成功        
    if re.compile(r"个人中心").search(resp.text):
        print('Login Success')
        return (cookies,1)
    else:
        print('Login failed')
        return (cookies,0)

这里需要注意的是:

1.并不是F12开发者工具截获的每个消息的COOKIE都可以用,必须选择Response Header里 status为200 OK的那个数据里的cookie

2.具体requests用get 方法还是post方法,需要针对获得的数据进行分析,看浏览器是执行了哪种操作,爬虫也执行相应的操作即可,这里判断是否登录成功,用get方法即可得到正确的结果,也可以利用status=200作为判断依据。

 

二、获取本月的记录总共几页

def getPageNum(cookies,beginDate,endDate):
    
    headers = {'User-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'}
    payload = {'opt':'list2','beginDate':beginDate,'endDate':endDate,'cids':'0',
               'bids':'0','sids':'0','pids':'0','memids':'0','order':'','isDesc':'0',
               'page':1,'note':'','mids':'0'}
    resp = requests.post(url,headers = headers, cookies = cookies, data = payload)
    data = json.loads(resp.text)
    #print(type(data)) 8个元素的dict
    pageCount = data['pageCount']
    return pageCount

这里的payload是从F12抓到的post的各个字段,每个都照抄下来,利用requests的post方法,即可抓取到需要的内容。

另外,注意到我们需要抓取的数据是在F12开发者工具的network里的XHR一项中,也就是动态加载得到的,那么我们得到的数据也需要json.load方法进行加载。然后在对加载后的数据进行分析,到底是多少个元素的列表还是字典之类的,直到解析到我们需要的数据。

三、具体爬取

def spider(doc,cookies,beginDate,endDate,pageNum): 
    
    headers = {'User-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'}
    
    for page in range(1,pageNum+1):
       
        payload = {'opt':'list2','beginDate':beginDate,'endDate':endDate,'cids':'0',
                   'bids':'0','sids':'0','pids':'0','memids':'0','order':'','isDesc':'0',
                   'page':page,'note':'','mids':'0'}
        resp = requests.post(url,headers = headers, cookies = cookies, data = payload)
    #    print(resp.text)
    
    
        data = json.loads(resp.text)
        #print(type(data)) 8个元素的dict
        
        groups = data['groups']#['list']
        #print(type(groups))  10个元素的list,每个元素是一个dict
        
        for n in range(0,len(groups)):#遍历多条记录
            group = groups[n]   
            item_list = group['list'] # 具体内容都在这个list下,类型:列表中具体几个元素,要看记录了几条
            
            
            for m in range(0,len(item_list)):
                item = item_list[m]  #   item 包含各个标签下的数据,为一个字典
                date_dic    = item['date']
                year        = date_dic['year'] + 1900
                month       = date_dic['month'] + 1
                day         = date_dic['date']
                categoryName = item['categoryName']
                memo        = item['memo']
                image_url   = item['url']
                
                date = '{}年{}月{}日'.format(str(year),str(month),str(day))
                print(date)
#                print(categoryName,memo,image_url)
                
                if m == 0:   #日期标题只输出一次
                    heading = doc.add_heading()
                    title = heading.add_run(date)
                    title.font.bold = True
                
                table = doc.add_table(rows= 1,cols=2)
                cells = table.rows[0].cells
                cells[0].text = categoryName
                cells[1].text = memo
                
                paragraph  = doc.add_paragraph(image_url)
#                table.cell(m,2).text = image_url
                if image_url and re.compile(r"http").search(image_url):
                    response = requests.get(image_url)
                    img = response.content
                    binary_img = BytesIO(img)  
                    doc.add_picture(binary_img, width=Inches(2))
                doc.save('D:/Code/python/Suispider/secret.doc')

1.本部分程序,将抓取到的记录保存到word文档中,传递给本函数的就有名称为doc的实例,后续将抓取到的结果保存到文档中,这里doc部分采用了python-docs包,包括添加标题add_heading, 添加表格 add_table,添加段落add_paragraph,等,具体用法可以参考https://python-docx.readthedocs.io/en/latest/。安装后调用的时候我记得报错了,后来安装对应的whl文件,才解决

2.另外,对于抓到的图片网址,像保存到word中,需要BytesIO方法将Bytes类型的图片数据直接保存到word,而不用下载到本地再弄到word中,这里参考了https://stackoverflow.com/questions/24341589/python-docx-add-picture-from-the-web

四、总的代码

# -*- coding: utf-8 -*-
"""
Created on Thu Nov 22 16:25:49 2018
创建爬取随手记记录的爬虫
@author: Jzz
"""
import requests
import sys
from bs4 import BeautifulSoup
import re
import json
import calendar  #为了确定终止时间是在某个月的几号
from docx import Document
from docx.shared import Inches
import io
import time


def Login(cookie_str):
    
    #浏览器登录后得到的cookie,一定要是Response Header里 status为200 OK的那个数据里的cookie
#    cookie_str = cookie
    #把cookie字符串处理成字典,以便接下来使用
    cookies = {}
    for line in cookie_str.split(';'):
        key, value = line.split('=', 1)
        cookies[key] = value
    
    #设置请求头
    #headers = {'User-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'}
    headers = {'User-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'}
    #在发送get请求时带上请求头和cookies
    #resp = requests.get(url, headers = headers, cookies = cookies) 
    #用get方法,得到的实际是https://www.sui.com/tally/new.do的结果,没有需要的数据
    
    resp = requests.get(url,headers = headers, cookies = cookies)

    #检查是否登录成功        
    if re.compile(r"个人中心").search(resp.text):
        print('Login Success')
        return (cookies,1)
    else:
        print('Login failed')
        return (cookies,0)

def getPageNum(cookies,beginDate,endDate):
    
    headers = {'User-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'}
    payload = {'opt':'list2','beginDate':beginDate,'endDate':endDate,'cids':'0',
               'bids':'0','sids':'0','pids':'0','memids':'0','order':'','isDesc':'0',
               'page':1,'note':'','mids':'0'}
    resp = requests.post(url,headers = headers, cookies = cookies, data = payload)
    data = json.loads(resp.text)
    #print(type(data)) 8个元素的dict
    pageCount = data['pageCount']
    return pageCount
      
def spider(doc,cookies,beginDate,endDate,pageNum): 
    
    headers = {'User-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'}
    
    for page in range(1,pageNum+1):
       
        payload = {'opt':'list2','beginDate':beginDate,'endDate':endDate,'cids':'0',
                   'bids':'0','sids':'0','pids':'0','memids':'0','order':'','isDesc':'0',
                   'page':page,'note':'','mids':'0'}
        resp = requests.post(url,headers = headers, cookies = cookies, data = payload)
    #    print(resp.text)
    
    
        data = json.loads(resp.text)
        #print(type(data)) 8个元素的dict
        
        groups = data['groups']#['list']
        #print(type(groups))  10个元素的list,每个元素是一个dict
        
        for n in range(0,len(groups)):#遍历多条记录
            group = groups[n]   
            item_list = group['list'] # 具体内容都在这个list下,类型:列表中具体几个元素,要看记录了几条
            
            
            for m in range(0,len(item_list)):
                item = item_list[m]  #   item 包含各个标签下的数据,为一个字典
                date_dic    = item['date']
                year        = date_dic['year'] + 1900
                month       = date_dic['month'] + 1
                day         = date_dic['date']
                categoryName = item['categoryName']
                memo        = item['memo']
                image_url   = item['url']
                
                date = '{}年{}月{}日'.format(str(year),str(month),str(day))
                print(date)
#                print(categoryName,memo,image_url)
                
                if m == 0:   #日期标题只输出一次
                    heading = doc.add_heading()
                    title = heading.add_run(date)
                    title.font.bold = True
                
                table = doc.add_table(rows= 1,cols=2)
                cells = table.rows[0].cells
                cells[0].text = categoryName
                cells[1].text = memo
                
                paragraph  = doc.add_paragraph(image_url)
#                table.cell(m,2).text = image_url
                if image_url and re.compile(r"http").search(image_url):
                    response = requests.get(image_url)
                    img = response.content
                    binary_img = BytesIO(img)  
                    doc.add_picture(binary_img, width=Inches(2))
                doc.save('D:/Code/python/Suispider/secret.doc')
                

#登录后才能访问的网页
url = 'https://www.sui.com/tally/new.rmi'
# 遍历不同账本,需要用不同的cookie即可实现,没有多余post参数

cookie_str = r'输入自己的cookie'
login_result = Login(cookie_str)
cookies = login_result[0]
set_year = 2018
doc = Document()

if login_result[1] == 1:
    for month in range(11,10,-1):
#    month = 11
        last_day  = calendar.monthrange(set_year,month)[1] #确定最后一天是几号
        beginDate = '{}.{}.01'.format(str(set_year),str(month))
        endDate   = '{}.{}.{}'.format(str(set_year),str(month),str(last_day))
        page_num  = getPageNum(cookies,beginDate,endDate)  #获取这个月记录了几页
        spider(doc,cookies,beginDate,endDate,page_num)
        time.sleep(5)
    

另外,如果有多个账本,想都爬取下来,只用使用不同的cookie即可,之前考虑是POST了什么参数,但是没有找到,只能用这种办法。

欢迎多多批评指正!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值