详解python爬取今日头条街拍美图
之前已经爬过今日头条街拍的美图,今天再次完善一下代码,并详解爬取过程及遇到的坑。废话不多说,抓紧上车啦。
分析页面
分析索引页
我们打开今日头条官网,在在搜索框输入「街拍」
然后点击确定,跳转到街拍的详情页。
这里可以看到上方有四个框,分别是 综合、视频、图集、用户。
两种方式
看到这里,就有两种不同的抓取方式。
- 抓取综合下方的图集,这个方式虽然可以抓取到图片,但是抓到的图片只有四张或一张,也就是看到的显示在标题下方的图片。而且获取的图片还不是高清的,还要替换每张图片的地址格式。
-
抓取图集下的图片,这种方式可以抓到所有一个标题下的图片,但是一页显示的图片抓取不到。
我看网上大多是第一种方式,这次为了练习,我们选取第二种方式。
我们点击图集,打开开发者工具「按F12」,不断下拉页面,页面地址没有变化,内容不断加载出来,这一看就是 Ajax 加载的页面。
这里面也有一些坑
- 如果你点击图集,打开开发者工具,刷新一下,你会发现,你的页面在综合这一栏。
-
你会发现你找到的上图的参数跟我的不一样。
这里你可以刷新之后点击图集,然后向下拖动几个,让页面多加载一些。
其中「cur_tab:3」这个参数中的数字对应图集,这下你明白了吧。
到这里就好办了,我们点击 Preview
可以看到 data 下方有 article_url 当然还有 image_url ,你点击 image_url 你会发现只有四个 url ,复制链接在浏览器上打开你发现 TMD 还不是大图,还是缩略图,所以我们不用它,我们获取 article_url ,获取之后再次请求不就完了吗。虽说麻烦,但是我们思路清晰,头脑发热,四肢简单。哎不对,跑题了。
分析详情页
这里我们来看看详情页的内容
这里我们随便点开一个组图的 url 来分析,我们可以看到返回的数据是一大堆 html ,这里有必要说一下, 我们在获取页面内容的时候,一般浏览器会返回给我们的是 response 里的内容。但是我们大多数爬取数据,用 xpath 、BeautifulSoup 获取数据,看的是 Elements 里的内容。这里一定要看看 response 里的内容和 Element 里的是否相同。
这里的图片地址还真是不好找,具体怎么找呢,点开图片的地址,复制下链接,在HTML里「Ctrl + F」就发现了。是在红色框里面的。
上代码
分析完了就开始上代码爬取
看看需要引入那些库
import requests import re,json,os from urllib.parse import urlencode from bs4 import BeautifulSoup from requests.exceptions import RequestException #引入模块config中所有变量 from config import * import pymongo from hashlib import md5 from multiprocessing import Pool
这里引用的库有点多,所有本文的干货也是满满滴。
获取索引页数据
def get_page_index(offset,keyword): # 获取页面的HTML data = { 'offset': offset, 'format': 'json', 'keyword': keyword, 'autoload': 'true', 'count': '20', 'cur_tab': 3, 'from':'gallery' } try: url = 'https://www.toutiao.com/search_content/?' + urlencode(data) response = requests.get(url) if response.status_code == 200: return response.text return None except RequestException: print('请求失败') return None
获取索引页的内容,这里的「offset」是页面的规律、「keyword」是关键字,我们这篇文章是街拍。通过构造参数,拼接 url 。返回页面的 text。
解析索引页
def parse_page_index(html): # 获取所有详情页的url data = json.loads(html) #页面是json格式的,装换成字符串格式 # data.keys()返回所有键名 if data and 'data' in data.keys(): for item in data.get('data'): yield item.get('article_url')
这个函数的主要作用就是提取所有的 article_url 。代码里面已经详细的说明了内容。
解析详情页的url
def get_page_detial(url): #请求详情页的url try: headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 ' '(KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4882.400 QQBrowser/9.7.13039.400'} response = requests.get(url,headers=headers) if response.status_code == 200: return response.text return None except RequestException: print('请求详情页失败') return None
这里不加 headers 是获取不到数据的。
解析详情页
def parse_page_detial(html): #获取详情页的标题和图片地址url soup = BeautifulSoup(html, 'lxml') title = soup.select('title')[0].get_text() #利用正则提取图片地址 pattern = re.compile('.*?gallery: JSON.parse\("(.*?)\"\)', re.S) result = re.search(pattern,html) if result: data = json.loads(result.group(1).replace('\\', '')) if data and 'sub_images' in data.keys(): sub_images = data.get('sub_images') #提取图片 images = [item.get('url') for item in sub_images] #保存图片到本地 for image in images:download_image(image) return {'title':title, 'image':images}
这里面有些东西要说一下了。
首先,这里获取的页面内容是 json 格式的,我们看一下这里的内容
这里获取用BeautifulSoup 获取 title 很方便,直接去第一个 title 就好了,关键就在这个image的提取。
这里是在红色框里的,这里涉及到了正则的用法,代码里用到了反斜杠,这里是转义匹配,要不然正则会匹配不到想要的数据。
还有在源代码中出现了好多反斜杠,不去除掉还是没办法匹配。
这些坑跨过之后就一帆风顺了。
保存到MongoDB
'''配置文件''' #链接地址 MONGO_URL = 'localhost' #数据库名称 MONGO_DB = 'jiepai' #表名称 MONGO_TABLE = 'jiepai' KEY_WORD = '街拍'
这是一些配置文件,注意,这里的配置文件是在另一个python文件中写的,所以说开头引入的库中有一个注释。
#引入模块config中所有变量 from config import * import pymongo #声明MongoDB对象 client = pymongo.MongoClient(MONGO_URL) db = client[MONGO_DB] def save_to_mongo(result): if db[MONGO_TABLE].insert(result): print('存储到MongoDB成功')
这里插入到MongoDB。
保存到本地
def save_image(result): file_path = '{0}/{1}{2}'.format(os.getcwd(),md5(result).hexdigest(),'jpg') if not os.path.exists(file_path): with open(file_path,'wb') as f: f.write(result)
这里用了 hashlib 库的 md5 这个方法,目的是为了防止图片的重复,这个方法会根据图片的内容生成唯一的字符串,用来去重最好不过了。
这里说保存图片,没有下载图片,怎么保存,所以还要先下载图片。
def download_image(url): try: print('正在下载',url) r = requests.get(url) if r.status_code == 200: save_image(r.content) return False except RequestException: print('请求图片出错') return False
细心的伙伴们已经发现,我们在解析详情页的时候插入的这个下载图片的函数。
开启多线程抓取
def main(offset): # 调用函数 html = get_page_index(offset,KEY_WORD) for url in parse_page_index(html): html = get_page_detial(url) if html: result = parse_page_detial(html) save_to_mongo(result) if __name__ == '__main__': pool = Pool() group = [x * 20 for x in range(1,21)] pool.map(main,group) pool.close() main()
这里声明一个线程池,调用 map 方法开启线程就可以了。
总结
到这里整个抓取过程就结束了。总体下来代码量要比平时抓取的要大,知识点也有很多。在这个过程中,即使找着代码敲也会发现不少的问题。抓取的过程就是不断调试的过程。
点个赞再走呗。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm调优
性能优化 JVM调优 Java程序性能优化 Tomcat Mysql Spring IOC Spring AOP Spring MVC Spring 5新特性 Mybatis 分布式架构 架构核心服务层技术 架构关键技术设施 分布式消息通讯 异步于MQ 分布式缓存 Redis Memcached MongoDB 数据存储 高并发分流技术Nginx 分布式解决方案 应用框架源码解读 微服务专题 你还不知道微服务?怎么加(zhuang)薪(bi) SpringBoot 与微服务的区别于联系 快速构建SpringBoot工程 SpringBoot核心组件剖析 快速集成mybatis实战 快速集成Dubbo及案例实战 构建集成 redis及案例实战 构建Swagger插件实现API 管理及接口测试体系 SpringCloud Zuul路由网关详解源码探析 Ribbon客户端负载均衡原理 Feign声明式服务调用方式 Eureka注册中心构件 Config配置服务中心 svn、git快速集成 Sleuth调用链路跟踪 BUS消息总线技术 Docker虚拟化技术 介绍、安装与使用 compose部...
- 下一篇
Java HashSet LinkedHashSet TreeSet类源码解析
Set集合中不含有重复的元素,插入重复的元素会失败。常用的有HashSet LinkedHashSet TreeSet。HashSet是无序的集合,LinkedHashSet中的排序和插入成功的顺序一致重复插入,TreeSet中元素是有序排列的,排序的依据是自身的comparator如果为null则根据key从小到大排序。HashSet和LinkedHashSet都是支持插入null的,TreeSet是否支持视comparator的情况,如果comparator不支持比较null的大小或者没有自定义的comparator则不支持插入null HashSet HashSet是基于HashMap实现的Set集合,所以支持插入null,但是不保持任何顺序。add成功时返回true,add已有元素时返回false。remove已有元素成功时返回true,remove不存在的元素时失败返回false。和HashMap一样是非线程安全类 public static void main(String args[]){ Set<String> set = new HashSet<&g...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS8编译安装MySQL8.0.19
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装Nodejs环境