ZSXQ爬虫

2019-11-15  本文已影响0人  kkjusdoit

加入了几个知识星球,鉴于精华帖阅读体验较差,想一次性爬下来,细细品读。于是开始了此次的爬虫任务:

网上找类似教程

原本打算网页端爬取,结果没找到合适的。(刚才又搜了下,好像这个是我真正想要的,看来还是的明确目标,多多搜索

一切从手机APP抓取实战——知识星球开始的。

按照基本步骤:

话不多说,上代码吧。
事先声明,拙劣的代码别质疑,质疑就是我菜。

先导入必要的模块
import requests 
import os
import time
import urllib.request
import urllib
requests.packages.urllib3.disable_warnings()  #防止警告
import ssl
ssl._create_default_https_context = ssl._create_unverified_context #全局取消证书验证
from datetime import date,timedelta

其中关于ssl._create_default_https_context = ssl._create_unverified_context #取消证书验证这个解决了我烦恼一时的图片无法下载问题。

使用python3.6进行 request请求时【出现问题的原因是“SSL:CERTIFICATE_VERIFY_FAILED”】的类似错误

请求头

等同于Pad访问,从Charles获取,重点是X-Request-Id和Authorization。

headers={
 'Host': 'api.zsxq.com' ,
    'X-Version': '1.10.30' ,
    'Accept': '*/*' ,
    'User-Agent': 'xiaomiquan/4.7.0 iOS/Pad/13.1.3',
    'Accept-Language': 'zh-Hans-CN;q=1',
    'X-Request-Id': 'XXXXXXXXXXX',
    'Authorization': 'XXXXXXXXXXX',
}
精华帖日期范围
start_to_end = []

#给定相差的天数,返回从开始到结束的全部天
def get_range(delta_days):
    start = date(2017,12,2)  #开始日期
    for i in range(delta_days):
        start_to_end.append(start)
        start += timedelta(days=1)
    return start_to_end

date_range =get_range(543) #从开始到543天后的每一天集合

str_daterange = [i.strftime(format='%Y %m %d') for i in date_range] #日期范围
right_date = str_daterange[1:]  #左  用于嵌入网址
left_date = str_daterange[:-1]  #右

重点:从给定链接下载精华帖的文字、评论及图片

据观察试验,链接形式如下:https://api.zsxq.com/v1.10/groups/2123521721/topics?count=20&begin_time={开始年份}%2D{月}%2D{日} T00%3A00%3A00%2E000%2B0800&end_time={结束年份}%2D{月}%2D{日}T23%3A59%3A59%2E000%2B0800&scope=digests'.
从某年某月某日到某年月日,按时间阶段搜此区间内的所有帖子。
但每条链接最大显示数量40个。

原本打算以周为间隔,每7天集结成一个文件夹。但存在2个问题:

  1. 昨天晚上,运行一段时间发现,有的文件夹空空如也。经查,发现是日期转换搞的鬼,date形式的2019-01-01转换为字符串成了2019-1-1,于是链接里月、日哪里少了0,因此无效链接,无法爬取数据;
  2. 大多数周的帖子总数远超40,甚至单日就将近40;
def crawl_from_url(url,dir_name):    #传入链接和一个文件夹名称
    if not os.path.exists(dir_name):    #是否存在名为dir_name的文件夹
        os.makedirs(dir_name)            #没有就新建个
    res = requests.get(url, headers=headers, verify=False)
    try:
        content = res.json()['resp_data']['topics']
        my_text = []
        m = n = 0

        for i in content:
            comments=[]
            img = 0
            #爬取主题文字和评论
            talk = i['talk']
            text =talk['text']
            try:
                for j in i['show_comments']:
                    comments.append(j['text'])
                my_text.append('\r\n'+'\r\n'+'【第{}个精华帖】'】[{}]'.format(n,i['create_time'])+'\r\n'+'\r\n'+'\r\n'+text+'\r\n')
                my_text = my_text+['\r\n'+'\r\n'+'【评论:】''\r\n'+'\r\n']+comments
            except KeyError:
                print('这个帖子没评论')
            print('第{}个精华帖下载完成'.format(n))
            n +=1

          
            try:                  #爬取图片
                for j in i['talk']['images']:
                    time.sleep(0.5)
                    dir = dir_name+'//'+str(n)+'_'+str(m)+'_'+'.jpg'
                    urllib.request.urlretrieve(j['large']['url'], dir)
                    print('下载成功第{}个精华帖的第{}个图片'.format(n,m))
                    m +=1
            except KeyError:
                print('第{}个精华帖没有图哦'.format(n))
            n +=1
        print('{}全部下载完成!'.format(dir_name))
        txt_path = dir_name+'//'+'dir_name.txt'
        with open(txt_path, 'w',encoding='utf-8') as f:
            f.writelines(my_text)
    except KeyError:
        print('当前日期没有帖子,下一个~')

这个函数是整个代码的核心,主要就是从json中找到文字、图片、评论等关系,然后一一提取即可。

可以注意到有好几个try...except...结构,这也是其中一个大坑:有的日期没帖子,有的帖子没评论,有的帖子没图,因此直接爬取会遭遇KeyError,用了try...except...后就可以跳过这些不存在的继续往下遍历。

还有个小坑是,往txt文件中写入换行符\n要带上\r\n,转义字符。

按每天来下载帖子

left_date: [2018 01 01... ... 2019 11 07]
right_date: [2018 01 02 ... ... 2019 11 08]
将left_date和right_date的年月日插入网址,形成链接,并以left_date日期为名新建文件夹。

for l,r in zip(left_date, right_date):
    url_by_day = 'https://api.zsxq.com/v1.10/groups/222588821821/topics?count=20&begin_time={}%2D{}%2D{}T00%3A00%3A00%2E000%2B0800&end_time=
{}%2D{}%2D{}T23%3A59%3A59%2E000%2B0800&scope=digests'.format(l[0:4],l[5:7],l[8:10],r[0:4],r[5:7],r[8:10])
    crawl_from_url(url_by_day,l[0:4]+l[5:7]+l[8:10])
历经1个半小时,终于下载完成!

[图片上传失败...(image-afd38-1573222234053)]

小结

学的零零散散的Python&爬虫,第一次派上用场,边摸索边试错,虽不甚完美,但自我感觉可以及格啦,希望以后继续多学、多用!

上一篇下一篇

猜你喜欢

热点阅读