hao同学的技术博客

  • 首页
  • Java
    • Java
    • JVM教程
    • Java面试
    • Java并发入门
    • Java并发进阶
  • 项目
    • 从零打造项目
  • Python
    • Python
    • Python爬虫
    • 算法
  • Java框架
    • Spring
    • SpringBoot
  • 前端
    • Angular
  • 其他
    • Linux
    • SQL
  • 随笔
分享技术,记录人生
一个痴迷于技术的厨艺爱好者
  1. 首页
  2. Python爬虫
  3. 正文

Scrapy 爬取今日头条街拍图片

2022年5月16日 393点热度 0人点赞 0条评论

Scrapy 爬取今日头条街拍图片插图

Python爬虫内容都是于2019上半年写的,关于某些网站的爬取技巧可能已经过时了,仅供参考。

之前用 requests 爬取过今日头条街拍的图片,当时只是爬取每篇文章的缩略图,今天尝试用 scrapy 来大规模爬取街拍详细图片。

分析页面

今日头条html页面

今日头条的内容是以 Ajax 加载而成的,我们爬取需要的是的 json 数据而非 html。

今日头条html页面

如上图所示,我们对爬取的 json 数据进行解析,即可得到文章标题,文章详细地址。

    def parse(self, response):
        text = response.text
        json_res = json.loads(text)

        if json_res.get('data'):
            for item in json_res.get('data'):
                # print(item)
                if item.get('cell_type') is not None:
                    continue
                title = item.get('title')
                if "toutiao" in item.get('article_url'):
                    it = ToutiaoJiapaiItem()
                    it['page_url'] = response.url
                    it['article_url'] = item.get('article_url')  # 详细网址
                    it['title'] = title  # 标题

                    yield Request(url=it['article_url'], headers=self.headers, callback=self.parse_page,
                                      meta={'item': it})

由于 json 数据中的图片列表,内容不全且都为缩略图,因此我们继续向下爬取。

分析详情页

在爬取过程中,发现详细页面大概有三种不同的页面展示。

文章中的图片

今日头条文章

这种文章较为普遍,从上往下欣赏图片。当对该类型的页面进行爬取内容时,虽然返回的是 html 内容,但是排版完全乱了。

今日头条文章html

利用正则匹配或者BeautifulSoup提取都比较麻烦,在这里,我采用的是对字符串进行截取处理,提取出有效内容。

        text = response.text
        str_list = text.split('pgc-img')
        if str_list != None:
            for i in range(1, len(str_list)):
                if ""http:" in str_list[i]:
                    pic_url = str_list[i].split('"')[2]
                    pic_list.append(pic_url)

图集

今日头条图集

这种是点击图片滑动欣赏图集,该页面返回的内容与上一种也不相同,因此需要另一种提取方式。

今日头条图集html

我们可以获取 JSON.parse 后的内容,将字符串转换为 json 进行提取。

# 利用正则提取图片地址
        pattern = re.compile('.*?gallery: JSON.parse\("(.*?)\"\)', re.S)
        result = re.search(pattern, text)
        if result:
            data = json.loads(result.group(1).replace('\\', ''))
            if data and 'sub_images' in data.keys():
                sub_images = data.get('sub_images')
                pic_list = [item.get('url') for item in sub_images]

小视频

最后一种是街拍小视频,在这里并没有对视频进行处理。

今日头条视频

最后,我们在 pipelines 文件里对获取到的 url 进行下载。

class ToutiaoJiepaiPipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        for image_url in item['photo_urls']:
            yield Request(image_url)

    def item_completed(self, results, item, info):
        image_paths = [x['path'] for ok,x in results if ok]
        if not image_paths:
            raise DropItem('图片未下载好')
        return item

效果如下。

今日头条图片爬取结果

详细代码如下:

import scrapy
import json
from scrapy_phantomjs.items import ToutiaoJiapaiItem
from urllib.parse import urlencode
from scrapy import Request
import re


class ToutiaoJiepaiSpider(scrapy.Spider):
    name = 'toutiao_jiepai'

    headers = {
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36'
    }

    def start_requests(self):
        # yield Request(url='https://www.toutiao.com/a6673629078630695427/', headers=self.headers,
        #               callback=self.parse_page)
        for i in range(0, 2):
            offset = i * 20
            params = {
                'aid': '24',
                'app_name': 'web_search',
                'offset': str(offset),
                'format': 'json',
                'keyword': '街拍',
                'autoload': 'true',
                'count': '20',
                'en_qc': '1',
                'cur_tab': '1',
                'from': 'search_tab',
                'pd': 'synthesis'
            }
            url = 'https://www.toutiao.com/api/search/content/?' + urlencode(params)

            yield Request(url=url, headers=self.headers, callback=self.parse)

    def parse(self, response):
        text = response.text
        json_res = json.loads(text)

        if json_res.get('data'):
            for item in json_res.get('data'):
                if item.get('cell_type') is not None:
                    continue
                title = item.get('title')
                if "toutiao" in item.get('article_url'):
                    it = ToutiaoJiapaiItem()
                    it['page_url'] = response.url
                    it['article_url'] = item.get('article_url')  # 详细网址
                    it['title'] = title  # 标题

                    yield Request(url=it['article_url'], headers=self.headers, callback=self.parse_page,
                                  meta={'item': it})

    def parse_page(self, response):
        item = response.meta['item']
        text = response.text

        pic_list = []

        str_list = text.split('pgc-img')
        if str_list != None:
            for i in range(1, len(str_list)):
                if ""http:" in str_list[i]:
                    pic_url = str_list[i].split('"')[2]
                    pic_list.append(pic_url)

        # 利用正则提取图片地址
        pattern = re.compile('.*?gallery: JSON.parse\("(.*?)\"\)', re.S)
        result = re.search(pattern, text)
        if result:
            data = json.loads(result.group(1).replace('\\', ''))
            if data and 'sub_images' in data.keys():
                sub_images = data.get('sub_images')
                pic_list = [item.get('url') for item in sub_images]
        item['photo_urls'] = pic_list

        yield item
本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可
标签: Python 爬虫
最后更新:2022年5月16日

hresh

这是一个专注于IT技术学习交流的个人技术博客网站,包括Java学习、Python爬虫、Web开发实践等领域,深耕Java领域,内容涵盖Java基础、Java并发编程、Java虚拟机、Java面试等核心知识点。

点赞
< 上一篇
下一篇 >

文章评论

取消回复

hresh

这是一个专注于IT技术学习交流的个人技术博客网站,包括Java学习、Python爬虫、Web开发实践等领域,深耕Java领域,内容涵盖Java基础、Java并发编程、Java虚拟机、Java面试等核心知识点。

文章目录
  • 分析页面
  • 分析详情页
最新 热点 随机
最新 热点 随机
后端必知:遵循Google Java规范并引入checkstyle检查 Spring Security结合Redis实现缓存功能 Spring Security结合JWT实现认证与授权 Spring Security自定义认证逻辑实现图片验证码登录 Spring Security进阶学习 Spring Security入门学习
Java面试准备之并发进阶一 Angular之NgForm学习 Python实现58 同城模拟登录 Spring AOP核心概念 String类之字符串常量池与intern方法 Java面试准备之Redis系列二

COPYRIGHT © 2022 hao同学的技术博客. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

鄂ICP备2022007381号

鄂公网安备 42010302002449号