能够爬取简书大部分数据,后续迭代较为方便
from os.path import sep, altsep
import requests
import json
import os
import re
class SimpleBook(object):
"""简书爬取,分类主题,主题下的单篇文章和作者还是有更新时间
# 模块分类
1.初始化方法
2.处理响应请求返回字节类型
3.文件操作
4.图片处理
5.处理每个url地址
6.对页面分类进行处理
"""
def __init__(self, page):
self.url = "https://www.jianshu.com" # 简书首页
self.headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/67.0.3396.99 Safari/537.36"}
self.proxy = {
'http': 'http://username:pasword@47.96.239.158:3128',
'https': 'http://username:pasword@47.96.239.158:3128'
}
self.page = page # 文章页码
self.subjects_url = [] # 主题页面地址list
self.subjects_title = [] # 主题类别list
def get_response(self, response_address):
"""主要用作获取响应体,response_address需传入url,返回值为字节流"""
# 返回字节流文本
return requests.get(response_address, headers=self.headers, proxies=self.proxy).content
def file_operation(self):
"""文件操作"""
# 1.创建保存数据的文件夹
if not os.path.exists("简书" + sep + "images"):
os.makedirs("简书" + sep + "images")
return
# 2.创建分类的json文件
self.classsubject = open("./简书/主题分类.json", "w+", encoding="utf-8")
# 3.创建文章简要json文件:标题,链接
self.article_briefly = open("./简书/文章简要.json", "a+", encoding="utf-8")
def image_processing(self, image_list):
"""图片保存下载,需要传入值image_list图片的url地址"""
# 1.图片名字,以'/'切割
file_name = [name.split(altsep)[-1] for name in image_list]
# 2.image二进制列表
image_bytes = [self.get_response(image_url) for image_url in image_list]
# 3.保存下载图片
try:
# 如果图片名字列表中有数据
if len(file_name) != 0:
with open("./简书/images" + "/" + file_name.pop(0), "wb+") as image:
image.write(image_bytes.pop(0))
# 我不想捕获一个已知的异常,"pop from empty list"
else:
return
except Exception as error:
print(error)
pass
def regular_matching_collections(self, topics_page=None, subject_html=None, article_page=None,
article_detail_html=None,
child_article_detail_html=None):
"""url,正则匹配处理集合
topics_page传入热门专题分类页码,默认为空
subject_html传入文章列表页面的源码,默认为空
article_page传入热门专题分类页面页码,默认为空
article_detail_html文章列表页面页码,默认为空
child_article_detail_html子文章详情页面页码,默认为空
参数不能空
"""
if topics_page:
# 1.更多热门专题地址页面url
return self.url + "/recommendations/collections?page={}&order_by=recommend".format(
topics_page)
elif article_page:
# 2.主题文章页面url,简书的前端文章采用的是滚动加载动画 https://www.jianshu.com/c/ad41ba5abc09
return '?order_by=added_at&page={}'.format(article_page)
elif subject_html:
# 3.主题分类 href="/c/ <h4 class="name">(.+)</h4>
# 手动对分类链接进行去重
subject_url_before = re.findall(r'href="(/c/\w+)', subject_html) # 未去重之前的地址list
subject_url_list = list(set(re.findall(r'href="(/c/\w+)', subject_html))) # 去重后顺序错误的地址list
subject_url_list.sort(key=subject_url_before.index) # 排序
title_list = re.findall(r'<h4 class="name">(.+)</h4>', subject_html) # 分类title
return title_list, subject_url_list
elif article_detail_html:
# 4.文章详情地址及文章标题 href="/p/a253c7be2a90">只有烂程序员才相信世界是由技术驱动的</a>
return re.findall(r'href="(/\w/\w+)">(.+)</a>', article_detail_html)
elif child_article_detail_html:
# 5.图片url地址 data-original-src="https://img.haomeiwen.com/i10014062/0fd9c472bee8702d.jpg
return re.findall(
r'data-original-src="(//upload-images.jianshu.io/upload_images/\d{8}-\w+.+)" data-orignal-width',
child_article_detail_html)
else:
raise ValueError("参数不能为空!")
def theme_subjects(self):
"""主题分类"""
# 热门分类页面
hot_html_list = [self.get_response(self.regular_matching_collections(topics_page=i + 1)).decode() for i in
range(2)]
# 获取热门分类的公众号title和url地址
list_tuple = [self.regular_matching_collections(subject_html=hot_html_list[i]) for i in range(2)]
# 重新整合热门分类title和url
title_list = list_tuple[0][0] + list_tuple[1][0]
url_list = list_tuple[0][1] + list_tuple[1][1]
# title和url写入文件中,使用标题表作为这个字典的键,转换为枚举类型取下标
subjects_dict = {}
for index, value in enumerate(title_list):
subjects_dict[value] = self.url + url_list[index]
# 转换为json
subjects_json = json.dumps(subjects_dict, ensure_ascii=False, indent=4)
self.classsubject.write(subjects_json)
def article_details(self):
"""文章简要,文章标题和url"""
# 读取主题分类json文件
self.classsubject.seek(0, 0)
load_dict = json.loads(self.classsubject.read())
# 读取主题分类字典,取出字典的值,组成页面地址的list
for keys, values in load_dict.items():
self.subjects_title.append(keys)
self.subjects_url.append(values)
dumps_dict = {} # 进行字典拼装,创建外部字典
# 先提取所有公众号的地址,采集每个页面里文章里的title和url
for index, url in enumerate(self.subjects_url):
dumps_dict[self.subjects_title[index]] = {} # 取出公众号的标题作为字典的键
# 进入某一分类的页面
for page in range(self.page):
# 拼接url并且返回页面
html = self.get_response(url + self.regular_matching_collections(article_page=page + 1)).decode()
# 获取页面里文章title和url,接收返回值文章list
article_list = self.regular_matching_collections(article_detail_html=html)
# 准备写入文章简要json文件, 文章地址,文章标题
for article_url, title in article_list:
dumps_dict[self.subjects_title[index]][title] = self.url + article_url
# 转换为json
subjects_json = json.dumps(dumps_dict, ensure_ascii=False, indent=4)
self.article_briefly.write(subjects_json)
# self.classsubject.close()
# self.article_briefly.close()
print("OK")
def pic_downloader(self):
"""图片下载器"""
# 进入文章子页面,读取文章简要json文件
self.article_briefly.seek(0, 0)
load_dict = json.loads(self.article_briefly.read())
for keywords in load_dict.keys():
# 提取字典中的文章的地址
single_page = load_dict[keywords] # 单个分类的所有文章标题和url
del single_page[keywords] # 删除多余的键值对
# 取出字典剩下所有的地址值,得到所有文章的源代码
page_list = [self.get_response(self.url + url).decode() for url in single_page.values()]
# 下载图片,图片地址list
image_url_list = [self.regular_matching_collections(child_article_detail_html=html) for html in page_list]
# 保存图片
for image_list in image_url_list:
self.image_processing(image_list)
# self.article_briefly.close()
def main():
"""主程序"""
run = SimpleBook(1) # page是控制文章列表的页码
run.file_operation()
run.theme_subjects()
run.article_details()
run.pic_downloader()
run.classsubject.close()
run.article_briefly.close()
pass
if __name__ == '__main__':
main()
regular_matching_collections
不是很满意,使用了很多if,elif,有思路的大兄弟,望留言
网友评论