Python爬虫-分析Ajax抓取今日头条街拍美图

Ajax

AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。

AJAX 是一种用于创建快速动态网页的技术。
通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
传统的网页(不使用 AJAX)如果需要更新内容,必须重载整个网页页面(html页面)。

例如
这里写图片描述
往下拉进度条,这个显示加载中的样式就是Ajax异步加载。

流程框架

  1. 分析Ajax的网页
  2. 分析街头美拍详细页面的网页组成
  3. 分析索引页内容
  4. 下载图片及保存数据库
  5. 开启循环和多进程
分析Ajax的网页

我们查看网页审查,分析Ajax加载的秘密。
首先动态加载肯定不是Doc目录下的,所以应该在XHR下查找。
这里写图片描述
根据观察以及往下拉网页我们会发现有一个?offset这个标签一直在刷新,而且每次都会增加偏移量20。然后我们找到Preview查找到响应的代码,在data标签下包含图片和标题。
这里写图片描述

分析街头美拍详细页面的网页组成

网页组成上面基本已经分析了,下面先看代码。
首先获取详情页的html页面

#根据url获取详情页的html页面
def get_detail_html(url):
    try:
        res = requests.get(url)
        if res.status_code != 200:
            print('请求详情页失败')
            return None
        print('请求详情页成功')
        html = res.text
        return html
    except RequestException:
        print('异常发生请求失败')
        return None

根据获取到的html解析有用数据

#根据html文件 抓取标题和urls
def parse_html(html):

    soup = BeautifulSoup(html, 'lxml')
    title = soup.select('title')[0].get_text()  #标题在 title标签下 直接获取即可
    print(title)

    #这个含有urls的json语句 位于 var gallery = 这个之后,所以我们做一个匹配
    pattern = re.compile(' var gallery = (.*?);')
    result = re.search(pattern, html)

    if result:
        # 该json包含2个元素
        # coust : 7
        # sub_images : url的list  这是我们需要查找的  这里面还包含了一个字典
        data = json.loads(result.group(1))
        # 查找sub_images是否存在
        if data and 'sub_images' in data.keys():
            sub_images = data.get('sub_images') #获取这个列表

            #获取所有键值为url的 values
            #images = [item['url'] for item in sub_images]
            images = [item.get('url') for item in sub_images]

            #每一张图片的url 传入 获取下载
            [download_image(url) for url in images]

            #将这一组信息传出去
            return {
                'title' : title,
                'urls' : images
            }

在其中每次解析到了图片url我们可以选择下载


#下载url对应的 html文件
def download_image(url):
    try:
        res = requests.get(url)
        if res.status_code != 200:
            print('下载失败')
            return None
        print('开始下载...')
        save_image(res.content) #二进制文本文件

    except RequestException:
        print('异常发生下载失败')
        return None

将下载的图片保存到本地

#将二进制信息保存到本地  也就是图片
def save_image(content):
    file_path = '{0}/{1}.{2}'.format(os.getcwd() + '/image',md5(content).hexdigest(), 'jpg')
    if not os.path.exists(file_path):
        with open(file_path, 'wb') as f:
            f.write(content)
            f.close()

我们即可得到以下打印信息

请求详情页成功
路人街拍,街拍女孩儿的牛仔裤特辑

开始下载...
开始下载...
开始下载...
开始下载...
开始下载...
开始下载...
开始下载...
{'title': '路人街拍,街拍女孩儿的牛仔裤特辑', 'urls': ['http://p3.pstatp.com/origin/22d1000035dd9b85559d', 
...']}

在项目的image文件夹下也包含下载的图片。

分析索引页内容

索引页的一个url包含一个图集,一个图集下包含很多图片。

#获取索引页内容  他是一个json格式的
#内容依旧是在 data下 包含标题和详情页url
def get_index_page(offset, keyword):
    header  = {
        'offset': offset,
        'format': 'json',
        'keyword': keyword,
        'autoload': 'true',
        'count': '20',
        'cur_tab': '1'
    }
    #例如第一个url是:
    # http://www.toutiao.com/search_content/?offset=0&format=json&keyword=%E8%A1%97%E6%8B%8D&autoload=true&count=20&cur_tab=1
    url = 'http://www.toutiao.com/search_content/?' + urlencode(header)
    try:
        res = requests.get(url)
        if res.status_code != 200:
            print('请求索引页失败')
            return None
        print('请求索引页成功')
        return res.text
    except RequestException:
        print('发生异常请求索引页失败')
        return None

获取到了整个索引页的html之后(注意这只是一次Ajax加载出现的内容,如需多次加载需要修改offset)需要即解析内容。

#获取索引页  某一次加载的全部 图集的标题和urls  这个urls即可进入详情页
def parse_index_html(html):
    jd = json.loads(html)
    data = jd['data']

    urls = [item['url'] for item in data]
    titles = [item['title'] for item in data]

    #当然也直接可以组成一个生成器,这样就可以直接使用for
    return dict(zip(titles, urls)) #组成字典返回

调用如下

def main():
    html = get_index_page('0', '街拍')
    for title,url in parse_index_html(html).items():
        detail_html = get_detail_html(url)
        print(parse_html(detail_html))

然后运行就可以在images目录下看到一堆图片了。

下载图片及保存数据库

下载图片上面已经提到了。
接下来试着分析数据以及保存数据。
数据分析模块,python有一个强大的第三方库那就是pandas。
Python Data Analysis Library 或 pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便捷地处理数据的函数和方法。你很快就会发现,它是使Python成为强大而高效的数据分析环境的重要因素之一。
保存方法

#为了将title和 urls组成一个list
#这个list包含2个参数  title 和 url的列表
def to_list(title, urls):
    return [title, str(urls)]


#保存到数据库
def save_to_sql(lst):

    #传入一个list参数
    df = pandas.DataFrame(lst)
    df.to_excel('urls.xlsx') #转换成Excel

    #存储到sql
    with sqlite3.connect('urls.sqlite') as db:
        df.to_sql('urls', con=db)

调用方式

def main():
    html = get_index_page('0', '街拍')
    lst = []
    for title,url in parse_index_html(html).items():
        detail_html = get_detail_html(url)
        dic = parse_html(detail_html)
        if dic is not None:
            lst.append(to_list(title, dic['urls']))
    save_to_sql(lst)

可以看到我们将所有的title和url列表 共同组成一个列表lst传入 save_to_sql以便保存这些数据。

运行之后我们可以查看我们的sql数据库和Excel表
这里写图片描述
这里写图片描述

开启循环和多进程

上述运行其实还是一个进程,速度也略慢。我们可以使用进程池加快速度!

这时我们需要给main一个参数,让不同的进程运行

def main(offset):
    html = get_index_page(str(offset), '街拍')
    lst = []
    for title,url in parse_index_html(html).items():
        detail_html = get_detail_html(url)
        dic = parse_html(detail_html)
        if dic is not None:
            lst.append(to_list(title, dic['urls']))
    save_to_sql(lst)

if __name__ == '__main__':

    pool = Pool()
    #因为url每次的偏移量为20
    pool.map(main, [x*20 for x in range(0,10+1)])

这里写图片描述
全部完成!
另外注意数据库存在了需要增加判断。。。以免重复创建而报错

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值