zoukankan      html  css  js  c++  java
  • 分析Ajax请求并抓取今日头条街拍美图

      通常我们从网页上爬取内容时,都是HTML代码,内容都已经写好了,直接从页面获取想要的信息即可,但是有的网页是通过ajax获取的数据,将ajax获取的数据通过json格式接受,然后展示在页面上的,也就是说,当我们打开一个页面时,首先请求的是他的html,然后HTML里面通过ajax获取后端数据,将数据以json格式展示在页面上。而近日头条就是这样。下面我们来看看。

      我们打开链接:https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D,我们发现下面图片的链接和我们粘贴复制过来的地址不一样,说明最终请求的数据通过了ajax请求,数据格式发生了改变。我们查看网页源码,发现页面中没有关于我们在头条中看到的信息。

    我们使用开发者选项F12,查看网页元素,发现请求头header中url与我们上面的连接不一样,增加了很多信息

    我们查看请求的参数,发现有很多参数,这就是通过ajax真正访问的数据连接,我们需要的就是将https://www.toutiao.com/search_content/?   +  加上下面的各种参数,就能查看到真正的数据源,

    下面是请求网页源数据的代码:

    #请求网页具体信息的函数
    def get_page_index(offset,keyword):
        data={
            'offset': offset,
            'format': 'json',
            'keyword': keyword,
            'autoload': 'true',
            'count': '20',
            'cur_tab':3,
            'from': 'search_tab'
        }
        url='https://www.toutiao.com/search_content/?'+urlencode(data)
        try:
            response = requests.get(url)
            if response.status_code == 200:
                return response.text
            return None
        except RequestException:
            return None

    接下来应该解析网页中的数据:我们通过上面的请求方式获得的就是通过ajax请求返回的json数据,这些数据中我们需要每一条头条的链接,下面是解析函数:

    def parse_page_index(html):
        data = json.loads(html)#将获取的ajax请求转换为json类型的数据
        if data and 'data' in data.keys():
            for item in data.get('data'):
                yield item.get('article_url')#从json数据中获取名为artile_url的数据

    接下来我们需要根据上面获得url请求每一条头条的内容:

    def get_page_datail(url):
        headers = {
            'User-Agent': 'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4)APPleWebKit/537.36(KHTML,like Gecko)Chrome/52.0.2743.116 Safari/537.36'
        }
        try:
            response = requests.get(url,headers=headers)
            if response.status_code == 200:
                return response.text
            return None
        except RequestException:
            print('出现错误')
            return None
    
    注意:这里我们添加了请求头,添加请求头的原因是有的网页防止python爬取数据,我们可以通过伪代理或者添加header的方式来避免。

    我们打开头条中的一条新闻,查看网页源代码,发现同样的我们看不到这条消息的数据,这些数据都包含在ajax请求返回的json数据中,我们需要从这些数据中提取

    我们需要从网页中解析,下面是代码:

    def pase_page_detail(html,url):
        soup=BeautifulSoup(html,'lxml')#使用beautifulsoup解析库来解析网页
        title = soup.select('title')[0].get_text()#直接可以通过标签名来获取头条的名称
        print(title)
        images_pattern  = re.compile('BASE_DATA.galleryInfo.*?gallery: JSON.parse("(.*?)"),',re.S)#这里我们使用正则表达式获取我们想要图片的信息
        result = re.search(images_pattern,html)
        if not result is None:#有的网页中不含有符合正则表达式的内容,我们直接将之过滤
            data=json.loads(result.group(1).replace('\',''))#将\转义替换为空字符,同时将图片的信息转为json格式
            if data and 'sub_images'in data.keys():#判断数据不为空并且里面含有图片的信息
                sub_images=data.get('sub_images')#从json数据中获取名为sub_images的内容
                images=[item.get('url') for item in sub_images]#有的新闻中含有多张图片,我们将图片的链接存在数组中
                for image in images:
                    get_save_image(image)#请求图片的链接
                return{
                    'title':title,
                    'url':url,
                    'image':images
                }#将我们得到的数据以数组格式返回,需要标题,url,还有图片链接

    接下来我们需要将这些数据存放到MongoDB数据库,首先定义几个静态变量,新建一个config.py的python文件

    MONGO_URL='localhost'#数据库的ip就是localhost
    MONGO_DB='toutiao'#存放的数据库名称
    MONGO_TABLE='toutiao'#存放的表名称

    在写代码的python文件中定义数据库:

    client = pymongo.MongoClient(MONGO_URL,connect=False)
    db = client[MONGO_DB]

    下面是存放到MongoDB的函数:

    def save_to_mongo(result):
        if db[MONGO_TABLE].insert(result):
            print('存储到数据库成功',result)
            return True
        return False

    我们还有将图片保存在本地的函数,这里我直接上全部代码:

    import json
    import os
    import re
    from hashlib import md5
    from multiprocessing import Pool
    
    from urllib.parse import urlencode
    
    import pymongo
    
    from config import *
    client = pymongo.MongoClient(MONGO_URL,connect=False)
    db = client[MONGO_DB]
    
    from bs4 import BeautifulSoup
    from requests.exceptions import RequestException
    import requests
    
    #请求网页具体信息的函数
    def get_page_index(offset,keyword):
        data={
            'offset': offset,
            'format': 'json',
            'keyword': keyword,
            'autoload': 'true',
            'count': '20',
            'cur_tab':3,
            'from': 'search_tab'
        }
        url='https://www.toutiao.com/search_content/?'+urlencode(data)
        try:
            response = requests.get(url)
            if response.status_code == 200:
                return response.text
            return None
        except RequestException:
            return None
    
    def parse_page_index(html):
        data = json.loads(html)#将获取的ajax请求转换为json类型的数据
        if data and 'data' in data.keys():
            for item in data.get('data'):
                yield item.get('article_url')#从json数据中获取名为artile_url的数据
    
    def get_page_datail(url):
        headers = {
            'User-Agent': 'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4)APPleWebKit/537.36(KHTML,like Gecko)Chrome/52.0.2743.116 Safari/537.36'
        }
        try:
            response = requests.get(url,headers=headers)
            if response.status_code == 200:
                return response.text
            return None
        except RequestException:
            print('出现错误')
            return None
    
    def pase_page_detail(html,url):
        soup=BeautifulSoup(html,'lxml')#使用beautifulsoup解析库来解析网页
        title = soup.select('title')[0].get_text()#直接可以通过标签名来获取头条的名称
        print(title)
        images_pattern  = re.compile('BASE_DATA.galleryInfo.*?gallery: JSON.parse("(.*?)"),',re.S)#这里我们使用正则表达式获取我们想要图片的信息
        result = re.search(images_pattern,html)
        if not result is None:#有的网页中不含有符合正则表达式的内容,我们直接将之过滤
            data=json.loads(result.group(1).replace('\',''))#将\转义替换为空字符,同时将图片的信息转为json格式
            if data and 'sub_images'in data.keys():#判断数据不为空并且里面含有图片的信息
                sub_images=data.get('sub_images')#从json数据中获取名为sub_images的内容
                images=[item.get('url') for item in sub_images]#有的新闻中含有多张图片,我们将图片的链接存在数组中
                for image in images:
                    get_save_image(image)#请求图片的链接
                return{
                    'title':title,
                    'url':url,
                    'image':images
                }#将我们得到的数据以数组格式返回,需要标题,url,还有图片链接
    
    def save_to_mongo(result):
        if db[MONGO_TABLE].insert(result):
            print('存储到数据库成功',result)
            return True
        return False
    
    def get_save_image(url):
        headers = {
            'User-Agent': 'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4)APPleWebKit/537.36(KHTML,like Gecko)Chrome/52.0.2743.116 Safari/537.36'
        }
        try:
            response = requests.get(url, headers=headers)
            if response.status_code == 200:
                save_image(response.content)
            return None
        except RequestException:
            print('请求图片界面错误')
            return None
    def save_image(content):
        file_path='{0}/{1}.{2}'.format(os.getcwd(),md5(content).hexdigest(),'jpg')
        if not os._exists(file_path):
            with open(file_path,'wb')as f:
                f.write(content)
                f.close()
    
    
    def main(offset):
        html=get_page_index(offset,'街拍')
        for url in parse_page_index(html):
            if url:
                html1=get_page_datail(url)
                if html:
                    result=pase_page_detail(html1,url)
                    if not result is None:
                        save_to_mongo(result)
    
    
    if __name__  == '__main__':
        groups = [x*2 for x in range(GROUP_START,GROUP_END+1)]
        pool = Pool()
        pool.map(main,groups)

    下面就是在MongoDB中的信息:

  • 相关阅读:
    sql 修改表名、列名、列类型
    .Net WinForm下配置Log4Net(总结不输出原因)
    ubuntu20.04 搭建门罗币节点
    python2 和 python3里StringIO和BytesIO的区别
    java.lang.IllegalArgumentException: java.lang.ClassCastException
    iphoneX安全边界
    ios中禁用回弹效果
    将nodejs回调方法变为promise
    实现trim方法
    flex实现三个div上中下布局
  • 原文地址:https://www.cnblogs.com/zll20153246/p/9671198.html
Copyright © 2011-2022 走看看