Python爬取今日头条搜索的照片。使用requests+正则表达式

news/2024/7/19 9:44:36 标签: python, 爬虫

爬取网页:http://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D

1,分析爬取页面,找到页面信息

在Chrome按F12打开开发者工具,查找网页内容的请求位置
找了doc中发现内容都是加载,查看JS内容页面内容无关。
在XHR中发现到我们想要的内容,页面内容是通过ajax加载进来的
这里写图片描述
查看Headers,可以得到Request URL和Query String,构造成完整的请求URL
这里写图片描述
编写请求索引页代码:

python">def get_index(offset, keyword):
    # 网页下拉后,页面重新加载新的内容,offset也增加20,因此offset和翻页有关
    # keyword刚好是我们要搜索的内容-街拍
    dict = {
        'offset': offset,
        'format': 'json',
        'keyword': keyword,
        'autoload': 'true',
        'count': '20',
        'cur_tab': '1'
    }
    # urlencode()把字典变成字符ASCII字符串
    # 构造索引页url
    url = 'http://www.toutiao.com/search_content/?' + urlencode(dict)
    print('索引页url' + url)

    try:
        res = requests.get(url)
        if res.status_code == 200:
            return res.text
        return None
    except RequestException:
        print('索引页请求失败')
        return None

2,分析索引页代码,得到详情页内容

这里写图片描述
在开发者工具里面查看到代码,发现是比较整齐的js代码,用json.loads载入代码,再经过处理就可以得到想要的信息
代码:

python">def parse_index(html):
    # 请求的链接返回的json文件,用json.loads载入变成字典,解析出每个详情页的url
    try:
        js = json.loads(html)
        if js and 'data' in js.keys():
            for item in js.get('data'):
                if item.get('article_url'):
                # 用生成器返回url
                    yield item.get('article_url')
    except JSONDecodeError:
        pass

3.请求详情页

请求详情页和索引页类似,复制粘贴详情页请求,加上if 内容==None判断跳过URL出错的异常

python">def get_detail(url):
    print('下载:' + url)
    if url != None:
        try:
            res = requests.get(url)
            if res.status_code == 200:
                return res.text
            return None
        except RequestException:
            print('详情页请求失败')
            return None

4.得到详情页信息

详情页的图片信息在Doc也就是正常html文件中,但是是通过需要通过js加载后进行解析
标题信息比较简单,用BeautifulSoup.select就可以查找到。
通过对比发现,网页有2种不同的页面,一种静态的下拉页面,一种是左右播放页面,两个页面title标题信息的获取是一致的,但是图片信息不同。
下拉式:
这里写图片描述
图片url代码在content后面,使用正则表达式解析可以得到
播放页面:
这里写图片描述
图片url代码在 gallery:里面,使用正则表达式匹配,然后分解后可以去掉一些文字,转换成js字典格式,就可以到url了
最后以字典的形式返回爬取的信息

python">def parse_detail(html, url):
    if html == None:
        return None
    # 通过BeautifulSoup来查找title
    soup = BeautifulSoup(html, 'lxml')
    title = soup.select('title')
    title = title[0].text if title else''
    # 因为有两个不一样的页面,所以有2个不一样的正则分析式
    images_pattern1 = re.compile('img src="(.*?);', re.S)
    images_pattern2 = re.compile('gallery: {(.*?)},.*?siblingLis', re.S)
    res = re.findall(images_pattern1, html)
    # 第一种页面,如果能匹配到内容就存储起来
    if res != []:
        results = [result.rstrip('&quot') for result in res]
        for ima in results: download_image(ima)
        return{
            'title': title,
            'url': url,
            'images': results
        }
    # 第二种页面,使用第二个正则表达式进行匹配,并储存结果
    else:
        res = re.search(images_pattern2, html)
        if res:
            data = json.loads(res.group(0).lstrip('gallery: ').rstrip('siblingLis').strip().rstrip(','))
            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,
                    'url': url,
                    'images': images
                }

5,下载,存储图片

python">def download_image(url):
    print('下载:'+url)
    try:
        res = requests.get(url)
        if res.status_code == 200:
            # 直接调用保持图片,传入参数网页的二进制信息
            save_iamge(res.content)      # res.contenst是二进制信息,因为下载图片需要二进制。
        return None
    except RequestException:
        print('详情页请求失败')
        return None


def save_iamge(content):
    # 构造保持路径, {0}为当前目录路径,{1}为md5生成值,避免重复下载,{2}为文件格式
    file_path = '{0}/images/{1}.{2}'.format(os.getcwd(), md5(content).hexdigest(), 'jpg')
    print(file_path)
    if not os.path.exists(file_path):   # 如果 路径文件不存在 就下载
        with open(file_path, 'wb') as f:
            f.write(content)    # 传入二进制信息
            f.close()

6,整合代码添加循环,爬取多页信息

python">import json
from json import JSONDecodeError
from urllib.parse import urlencode
from hashlib import md5
import re
import os
from requests.exceptions import RequestException
import requests
from bs4 import BeautifulSoup


def get_index(offset, keyword):
    # 网页下拉后,页面重新加载新的内容,offset也增加20,因此offset和翻页有关
    # keyword刚好是我们要搜索的内容-街拍
    dict = {
        'offset': offset,
        'format': 'json',
        'keyword': keyword,
        'autoload': 'true',
        'count': '20',
        'cur_tab': '1'
    }
    # urlencode()把字典变成字符ASCII字符串
    # 构造索引页url
    url = 'http://www.toutiao.com/search_content/?' + urlencode(dict)
    print('索引页url' + url)

    try:
        res = requests.get(url)
        if res.status_code == 200:
            return res.text
        return None
    except RequestException:
        print('索引页请求失败')
        return None


def parse_index(html):
    # 请求的链接返回的json文件,用json.loads载入变成字典,解析出每个详情页的url
    try:
        js = json.loads(html)
        if js and 'data' in js.keys():
            for item in js.get('data'):
                if item.get('article_url'):
                    yield item.get('article_url')
    except JSONDecodeError:
        pass


def get_detail(url):
    print('下载:' + url)
    if url != None:
        try:
            res = requests.get(url)
            if res.status_code == 200:
                return res.text
            return None
        except RequestException:
            print('详情页请求失败')
            return None


def parse_detail(html, url):
    if html == None:
        return None
    # 通过BeautifulSoup来查找title
    soup = BeautifulSoup(html, 'lxml')
    title = soup.select('title')
    title = title[0].text if title else''
    # 因为有两个不一样的页面,所以有2个不一样的正则分析式
    images_pattern1 = re.compile('img src="(.*?);', re.S)
    images_pattern2 = re.compile('gallery: {(.*?)},.*?siblingLis', re.S)
    res = re.findall(images_pattern1, html)
    # 第一种页面,如果能匹配到内容就存储起来
    if res != []:
        results = [result.rstrip('&quot') for result in res]
        for ima in results: download_image(ima)
        return{
            'title': title,
            'url': url,
            'images': results
        }
    # 第二种页面,使用第二个正则表达式进行匹配,并储存结果
    else:
        res = re.search(images_pattern2, html)
        if res:
            data = json.loads(res.group(0).lstrip('gallery: ').rstrip('siblingLis').strip().rstrip(','))
            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,
                    'url': url,
                    'images': images
                }


def download_image(url):
    print('下载:'+url)
    try:
        res = requests.get(url)
        if res.status_code == 200:
            # 直接调用保持图片,传入参数网页的二进制信息
            save_iamge(res.content)      # res.contenst是二进制信息,因为下载图片需要二进制。
        return None
    except RequestException:
        print('详情页请求失败')
        return None


def save_iamge(content):
    # 构造保持路径, {0}为当前目录路径,{1}为md5生成值,避免重复下载,{2}为文件格式
    file_path = '{0}/images/{1}.{2}'.format(os.getcwd(), md5(content).hexdigest(), 'jpg')
    print(file_path)
    if not os.path.exists(file_path):   # 如果 路径文件不存在 就下载
        with open(file_path, 'wb') as f:
            f.write(content)    # 传入二进制信息
            f.close()


def main(offset):
    urls = get_index(offset, '街拍')
    for url in parse_index(urls):
        res = get_detail(url)
        parse_detail(res, url)

    # # 测试单个页面:
    # url = 'https://temai.snssdk.com/article/feed/index?id=3972873&subscribe=6768458493&source_type=24&content_type=2&create_user_id=6100&classify=2&adid=__AID__'
    # res = get_detail(url)
    # print(parse_detail(res, url))


if __name__ == '__main__':
    # 传入翻页内容,每次offset变化20,因此0-10也每次*20
    for i in range(0, 10):
        main(i*20)

http://www.niftyadmin.cn/n/1736797.html

相关文章

设计模式大总结-创建型模式

上一篇简单的介绍了下设计模式的定义、原则和分类,现在我将分别介绍一下这几23个设计模式。 今天我要说的是创建型模式,它包括简单工厂模式、抽象工厂模式、工厂方法模式、单例模式、建造者模式和原型模式。 1、简单工厂模式 主要用于创建对象。添加新…

Python爬取淘宝搜索页,使用Selenium+BeautifulSoup

使用Selenium驱动chrome页面,获得淘宝信息并用BeautifulSoup分析得到结果 使用Selenium时注意页面的加载判断,以及加载超时的异常处理 import json import re from bs4 import BeautifulSoup from selenium import webdriver from selenium.common.exc…

设计模式大总结2-结构型模式

上篇我们介绍完了创建型模式,今天我们继续总结结构型模式,它分别包括适配器模式、装饰模式、桥接模式、组合模式、享元模式、代理模式和外观模式。 1、适配器模式 定义:将一个类的接口转换成客户希望的另外一个接口。--------------双方都不…

Python list-列表

Python list-列表 列表的内部结构 头部保存元素数量,内存分配计数独立数组存储元素指针操作时间复杂度 操作时间复杂度复制O(N)添加元素(在尾部添加)O(1)插入元素(在指定位置插入)O(N)获取元素O(1)修改元素O(1)删除元素O(N)遍历O(N)获取长度为k的切片O(k)删除切片…

设计模式大总结3-行为型模式

上篇讲到了结构型模式和创建型模式,那么设计模式目前没有介绍的只有行为型模式了,行为型模式比较多,共有11个,他们分别是观察者模式、模板模式、命令模式、状态模式、策略模式、中介者模式、访问者模式、解释器模式、备忘录模式、…

Python dict-字典

Python dict-字典 映射(mapping)结构,基于哈希表存储键值对数据 key必须是可哈希类型 哈希冲突时,采用开放寻址法 散列表是一个稀疏数组。1/3表元为空,因此空间效率低 散列表里元素通常叫做表元(bucke…

安卓----SQLite数据库和对话框

现在介绍一下安卓如何操作数据库和几种常见的安卓对话框。老规矩,用一张图来介绍今天的内容。 图片看不清的话可以右键新窗口打开 一、SQLite数据库 SQLite,是一款轻量型的数据库,是遵守 ACID(原子性、一致性、隔离性、持久性)的关联式数据库…

Python Flask_caching-缓存

Python Flask_caching-缓存 安装: pip install Flask-Caching初始化使用演示 # app.py app Flask(__name__) cache Cache(app, config{CACHE_TYPE : simple}) app.extensions[cache_key] cache# ***.py # 调用 .cache 返回cache对象 cache curren…