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

本文介绍Ajax技术原理及其在网络爬虫中的应用,重点讲解如何利用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)])

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值