闲得流口水之爬取头条MM(MM勿进)

都2020年了还没爬过今日头条,你做爬虫是不是显得OUT了?但是没事,虽然现在的接口都变化了,那我就讲下2020年怎么搞今日头条妹子写真,这是一个改进的项目,里面参加了我自己的很多想法,比如有些很难懂的,我自己用简单的方式去实现了它,个人感觉还是实现的不错的,各位看官可以看看。

这个妹子觉得好看的评论区扣好看,直接教你怎么搞到手!

项目介绍:

利用简单的进程池和Ajax数据爬取技术对今日头条关键词页面进行分析和处理,然后获取每个页面的链接,从而获得所有图片的链接,然后打包下载,

整个步骤我都会用小模块代码将其展示,实现不了的过来砍我! 就是这么的负责我跟你们说。

项目技术:

简单的进程池:

这里对进程的了解我也不是很多,简单的说下项目需要的函数:

from multiprocessing import Pool  # 调用函数库p = Pool(4)  #  构造一个进程池,单位为4p.close()  # 关闭进程p.join()  # 开启进程

对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。

Ajax数据爬取:

网址的很多信息都不会直接全部出现在源代码里面,比如你刷网页,那些新刷出的网页就是一个个的通过ajax接口加载出来的,这是一种异步加载方式,原始的页面不会包含很多数据,数据都放在一个个接口里面,只有我们请求这个ajax接口,然后服务器后台收到这个接口信息,才会把数据返回,然后JavaScript分析这个数据,在渲染到浏览器页面上,这就是我们看到的模式,

现在越来越多的网页都是采用这个异步加载的方式,爬虫就现得没那么容易了,这个概念的讲的也拗口,我们直接开始实战吧!

项目作业:

最终作业效果图:

分析ajax接口获得数据:

数据包括:

每个页面的标题

每个页面的网址

目标网址: 今日头条关键词妹子

怎么知道他是不是ajax接口,主要有三点:

第一点

注意我这几个箭头,只要你在这里·查找·里面找不到与文章对应的文字还是链接什么的,那就可能是。

第二点

在这个XHR里面找到箭头的网址,点击,查看预览,这个时候你随意打开里面的东西,就能发现很多与文章相同的点

第三点

还是这张图,你可以看到X-requested里面的接口是XMLHttpRequets

如果三点同时满足,那他就是Ajax接口,然后异步加载出来的数据。

获得数据

在第二点的那张图我们可以看到有0,1,2,3,4,之类的,打开你会发现,都在这里面,图中我用箭头标红了,有标题和页面链接,只要获得这个页面链接,那么就很简单了。

编写程序:

获得json文件:

首先请求最开始的页面: 美女_头条搜索

但是我们不能这样直接把页面交给requests库直接干,因为这是一个ajax接口,如果不加入参数,很可能让你输入什么验证码还是拉动验证条什么,反正就是很麻烦,那我们就加入参数,具体措施如下:

def get_page(offset): # offset偏移,因为每个ajax都是加载固定的页面数

                    # 这里是20,在第三点图上可以看得到

    global headers  # 全局变量  我后面还要用

    headers = {

        'cookie': 'tt_webid=6821518909792273933; WEATHER_CITY=%E5%8C%97%E4%BA%AC; SLARDAR_WEB_ID=b4a776dd-f454-43c6-81cd-bd37cb5fd0ec; tt_webid=6821518909792273933; csrftoken=4a2a6afcc9de4484af87a2ff8cba0638; ttcid=8732e6def0484fae975c136222a44f4932; s_v_web_id=verify_k9o5qf2w_T0dyn2r8_X6CE_4egN_9OwH_CCxYltDKYSQj; __tasessionId=oxyt6axwv1588341559186; tt_scid=VF6tWUudJvebIzhQ.fYRgRk.JHpeP88S02weA943O6b6-7o36CstImgKj1M3tT3mab1b',

        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68',

        'referer': 'https://www.toutiao.com/search/?keyword=%E7%BE%8E%E5%A5%B3',

        'x-requested-with': 'XMLHttpRequest'

    }  # 头信息 加入参数

    params = {

        'aid': ' 24',

        'app_name': ' web_search',

        'offset': offset,

        'format': ' json',

        'keyword': ' 美女',

        'autoload': ' true',

        'count': ' 20',

        'en_qc': ' 1',

        'cur_tab': ' 1',

        'from': ' search_tab',

        'pd': ' synthesis',

        'timestamp': int(time.time())

    }

    url = 'https://www.toutiao.com/api/search/content/?' + urlencode(params)  # 构造url, 使用到了urlencode() 函数

    url = url.replace('=+', '=')  # 这里必须注意现在的网址根本不一样

    # print(url)         

    try:

        r = requests.get(url, headers=headers, params=params)

        r.content.decode('utf-8')

        if r.status_code == 200:

            return r.json()  # 返回json格式 因为全是字典类型

    except requests.ConnectionError as e:

        print(e)

这里必须注意一点,请求的网址已经改掉了,我在代码里面给了解释,仔细看看。

def get_image(json): # 获取图片

    if json.get('data'):  # 如果这个存在

        for item in json.get('data'):

            if item.get('title') is None:

                continue  # 如果标题是空值

            title = item.get('title')  # 获取标题

            if item.get('article_url') == None:

                continue

            url_page = item.get('article_url')

            # print(url_page)

            rr = requests.get(url_page, headers=headers)

            if rr.status_code == 200:

                pat = '<script>var BASE_DATA = .*?articleInfo:.*?content:(.*?)groupId.*?;</script>'  #  用正则大致匹配一下范围

                match = re.search(pat, rr.text, re.S)

                if match != None:

                    result = re.findall(r'img src&#x3D;\\&quot;(.*?)\\&quot;', match.group(), re.S)


                #  print(i.encode('utf-8').decode('unicode_escape')

                    # 转换编码方式 把\u之类的改掉

                    yield {

                        'title': title,

                        'image': result

                    }

这里获取的网页链接都是Unicode格式的,在后面的下载部分,我给了修改方案,这也是一个暗坑。

def save_image(content):

    path = 'D://今日头条美女//'  # 目录

    if not os.path.exists(path):  # 创建目录

        os.mkdir(path)

        os.chdir(path)

    else:

        os.chdir(path)

    # ------------------------------------------

    if not os.path.exists(content['title']):  # 创建单个文件夹

        if '\t' in content['title']:  # 以title为标题创建单个文件夹

            title = content['title'].replace('\t', '')  # 去除特殊符号 不然创建不了文件名称

            os.mkdir(title + '//')

            os.chdir(title + '//')

            print(title)

        else:

            title = content['title']

            os.mkdir(title + '//')  # 创建文件夹

            os.chdir(title + '//')

            print(title)

    else:  # 如果存在

        if '\t' in content['title']:  # 以title为标题创建单个文件夹

            title = content['title'].replace('\t', '')  # 去除特殊符号 不然创建不了文件名称

            os.chdir(title + '//')

            print(title)

        else:

            title = content['title']

            os.chdir(title + '//')

            print(title)

    for q, u in enumerate(content['image']):  # 遍历图片地址列表

        u = u.encode('utf-8').decode('unicode_escape')

        # 先编码在解码 获得需要的网址链接

        #  开始下载

        r = requests.get(u, headers=headers)

        if r.status_code == 200:

            # file_path = r'{0}/{1}.{2}'.format('美女', q, 'jpg')  # 文件的名字和地址,用三目运算符来调试文件夹的名字

            # hexdisgest() 返回十六进制图片

            with open(str(q) + '.jpg', 'wb') as fw:

                fw.write(r.content)

                print(f'该系列----->下载{q}张')

在U变量的时候进行了编码在解码操作,然后网址就正常很多了。

项目全部代码:

# -*- coding '':'' utf-8 -*-''

# @Time      '':''  2020/5/1  9:34''

# @author    '':''  沙漏在下雨''

# @Software  '':''  PyCharm''

# @CSDN      '':''  https://me.csdn.net/qq_45906219''

import requests

from urllib.parse import urlencode  # 构造url

import time

import os

from hashlib import md5

from lxml import etree

from bs4 import BeautifulSoup

import re

from multiprocessing.pool import Pool

def get_page(offset):

    global headers

    headers = {

        'cookie': 'tt_webid=6821518909792273933; WEATHER_CITY=%E5%8C%97%E4%BA%AC; SLARDAR_WEB_ID=b4a776dd-f454-43c6-81cd-bd37cb5fd0ec; tt_webid=6821518909792273933; csrftoken=4a2a6afcc9de4484af87a2ff8cba0638; ttcid=8732e6def0484fae975c136222a44f4932; s_v_web_id=verify_k9o5qf2w_T0dyn2r8_X6CE_4egN_9OwH_CCxYltDKYSQj; __tasessionId=oxyt6axwv1588341559186; tt_scid=VF6tWUudJvebIzhQ.fYRgRk.JHpeP88S02weA943O6b6-7o36CstImgKj1M3tT3mab1b',

        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36 Edg/81.0.416.68',

        'referer': 'https://www.toutiao.com/search/?keyword=%E7%BE%8E%E5%A5%B3',

        'x-requested-with': 'XMLHttpRequest'

    }  # 头信息 加入参数

    params = {

        'aid': ' 24',

        'app_name': ' web_search',

        'offset': offset,

        'format': ' json',

        'keyword': ' 美女',

        'autoload': ' true',

        'count': ' 20',

        'en_qc': ' 1',

        'cur_tab': ' 1',

        'from': ' search_tab',

        'pd': ' synthesis',

        'timestamp': int(time.time())

    }

    url = 'https://www.toutiao.com/api/search/content/?' + urlencode(params)  # 构造url

    url = url.replace('=+', '=')  # 网址根本不一样

    # print(url)

    try:

        r = requests.get(url, headers=headers, params=params)

        r.content.decode('utf-8')

        if r.status_code == 200:

            return r.json()  # 返回json格式 因为全是字典类型

    except requests.ConnectionError as e:

        print(e)

def get_image(json):  # 获取图片

    if json.get('data'):  # 如果这个存在

        for item in json.get('data'):

            if item.get('title') is None:

                continue  # 如果标题是空值

            title = item.get('title')  # 获取标题

            # if item.get('image_list') is None:  # 进行判空

            #    continue

            # urls = item.get('image_list')  # 获得图片网址

            # for url in urls:  # 遍历这个urls

            #    url = url.get('url')

            #    # 使用正则拼接网址

            #    url = 'http://p1.pstatp.com/origin/' + 'pgc-image/' + url.split('/')[-1]

            if item.get('article_url') == None:

                continue

            url_page = item.get('article_url')

            # print(url_page)

            rr = requests.get(url_page, headers=headers)

            if rr.status_code == 200:

                pat = '<script>var BASE_DATA = .*?articleInfo:.*?content:(.*?)groupId.*?;</script>'

                match = re.search(pat, rr.text, re.S)

                if match != None:

                    result = re.findall(r'img src&#x3D;\\&quot;(.*?)\\&quot;', match.group(), re.S)

                    # for i in result:

                    #    print(i.encode('utf-8').decode('unicode_escape')

                    # 转换编码方式 把\u之类的改掉

                    yield {

                        'title': title,

                        'image': result

                    }

            #  格式出错,这里产生了十六进制的数值, 网址获取不了,明天看

            # yield {

            #    'title': title,

            #    'image': url

            # }  # 返回标题和网址

def save_image(content):

    path = 'D://今日头条美女//'  # 目录

    if not os.path.exists(path):  # 创建目录

        os.mkdir(path)

        os.chdir(path)

    else:

        os.chdir(path)

    # ------------------------------------------

    if not os.path.exists(content['title']):  # 创建单个文件夹

        if '\t' in content['title']:  # 以title为标题创建单个文件夹

            title = content['title'].replace('\t', '')  # 去除特殊符号 不然创建不了文件名称

            os.mkdir(title + '//')

            os.chdir(title + '//')

            print(title)

        else:

            title = content['title']

            os.mkdir(title + '//')  # 创建文件夹

            os.chdir(title + '//')

            print(title)

    else:  # 如果存在

        if '\t' in content['title']:  # 以title为标题创建单个文件夹

            title = content['title'].replace('\t', '')  # 去除特殊符号 不然创建不了文件名称

            os.chdir(title + '//')

            print(title)

        else:

            title = content['title']

            os.chdir(title + '//')

            print(title)

    for q, u in enumerate(content['image']):  # 遍历图片地址列表

        u = u.encode('utf-8').decode('unicode_escape')

        # 先编码在解码 获得需要的网址链接

        #  开始下载

        r = requests.get(u, headers=headers)

        if r.status_code == 200:

            # file_path = r'{0}/{1}.{2}'.format('美女', q, 'jpg')  # 文件的名字和地址,用三目运算符来调试文件夹的名字

            # hexdisgest() 返回十六进制图片

            with open(str(q) + '.jpg', 'wb') as fw:

                fw.write(r.content)

                print(f'该系列----->下载{q}张')

def main(offset):

    json = get_page(offset)

    get_image(json)

    for content in get_image(json):

        try:

            # print(content)

            save_image(content)

        except FileExistsError and OSError:

            print('创建文件格式错误,包含特殊字符串:')

            continue

if __name__ == '__main__':

    pool = Pool()

    groups = [j * 20 for j in range(8)]

    pool.map(main, groups) # 传offset偏移量

    pool.close()

    pool.join()

项目修复:

正确的拼接网址,修复了data = None 的bug,在获得json文件里面得到了体现

加入必要的参数,避免了验证码和验证条的出现,这也很棒 =。=

进行编码解码操作, 修改了\u格式下的链接不匹配问题,在获得网址的时候我也提到了

下载图片的时候使用了子文件夹的处理,让下载的图片不会那么杂乱

下载采用了简单的线程池问题,加快了下载的速度

更多学习课程以及资料 加Q群313074041领取

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345