Python爬虫入门—分析Ajax爬取今日头条美图

Python爬虫入门—分析Ajax爬取今日头条美图

声 明

代码是反复看视频,最后理解敲下来,不是原创。来源:Python3爬虫三大案例实战分享 - 网易云课堂 感谢崔大神@静觅

目 的

学习交流。我也是刚开始学习python(2017.09.08开始),想通过写文章促进学习~

觉得不错的点个赞,有问题欢迎留言交流~

学习资料:

新知识:

  • md5的使用方法;
  • 多进程pool.map();
  • pymongo、MongoDB和urlencode的使用

结果图

  • 数据库

爬取流程:

1.环境配置

Anaconda+Mongodb(MongoDB for GIANT Ideas)、Robo 3T(可视化Robo 3T)+

基本库:

2.了解Ajax

AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

AJAX 教程 | 菜鸟教程

3.爬取思路

a.抓取和分析索引页

  • 抓取索引页
索引页
def get_page_first(offest,keyword):#抓取索引页
 #如何获得data:F12-network-F5-XHR-Headers-Query string 
    data={
        'offset':offest,#offest可变
        'format':'json',
        'keyword':keyword,#keyword是可以自定义 
        'autoload':'true',
        'count':'20',
        'cur_tab':3
    }   
 #urlencode可以把字典对象变成url的请求参数 (from urllib.parse import urlencode)
    url='http://www.toutiao.com/search_content/?'+urlencode(data) 
    try:
        response=requests.get(url) #请求url
        if response.status_code==200:
            return response.text
        return None
    except RequestException:
        print('请求异常')
        return None
  • 分析索引页
def parse_page_first(html):
    data=json.loads(html) #转换成json对象
    if data and 'data' in data.keys():#data这个对象非空 并且 这个对象里有叫'data'的key
        for item in data.get('data'):
            yield item.get('article_url') #构造一个生成器,把所有的article_url解析出来

b.抓取详情页的内容

详情页

抓取详情页

def get_page_detai(url):#详情页url
    try:
        response=requests.get(url) #请求url
        if response.status_code==200:
            return response.text
        return None
    except RequestException:
        print('请求异常')
        return None

分析详情页

#第一步,获取每一组图片的总链接(包含各种信息:title\image...)
#第二步,获取每组图中每张图片的链接(只需要图片链接)
def parse_page_chirld(htmlchirld,url):#详情页url以及HTML
    soup=BeautifulSoup(htmlchirld,'lxml')
    title=soup.select('title')[0].get_text()
    print(title)
    images_pattern=re.compile('gallery: (.*?),\n',re.S)
    result = re.search(images_pattern, htmlchirld)
    if result:#判断是否成功
        data = json.loads(result.group(1))  # 对字符串进行解析,把字符串转化成json对象
        if data and 'sub_images' in data.keys():  # 判断里面是否含有我们想要的数据
            sub_images = data.get('sub_images')
            images_url=[item.get('url') for item in sub_images]
            for image in images_url: download_image(image)
            return {
                'title': title,
                'url': url,
                'images_url': images_url
            }
#下载图片
def download_image(url):
    print('正在下载',url)
    try:
        response=requests.get(url)
        if response.status_code==200:
            #return response.text
            save_image(response.content)#content二进制(图片是以二进制的方式保存在计算机中)
        return None
    except RequestException:
        print('请求图片出错',url)
        return None
#保存图片
def save_image(content):
    file_path='{0}/{1}.{2}'.format('D:\jiepai',md5(content).hexdigest(),'jpg')
    if not os.path.exists(file_path):
        with open(file_path,'wb') as f:
            f.write(content)
            f.close()

c.保存到数据库

  • 新建config.py
#  from config import * 将config.py中的所有变量引入
MONGO_URL='localhost'#数据库地址
MONGO_DB='toutiao'#数据库名称
MONGO_TABLE='toutiao'#表格名称

GROUP_START=1
GROUP_END=5#循环圈数
KEYWORD='街拍'#可以随便改

完整代码

import requests
from urllib.parse import urlencode
import json
from hashlib import md5
from bs4 import BeautifulSoup
import re
import os
from requests.exceptions import RequestException
import pymongo
from config import *
#from multiprocessing import Pool
client=pymongo.MongoClient(MONGO_URL)
db=client[MONGO_DB]
def get_page_first(offest,keyword):#抓取首页
    data={
        'offset':offest,#offest可变
        'format':'json',
        'keyword':keyword,#keyword是可以自定义
        'autoload':'true',
        'count':'20',
        'cur_tab':3
    }
    url='http://www.toutiao.com/search_content/?'+urlencode(data)
    try:
        response=requests.get(url) #请求url
        if response.status_code==200:
            return response.text
        return None
    except RequestException:
        print('请求异常')
        return None
def parse_page_first(html):
    data=json.loads(html)#转换成json对象
    if data and 'data' in data.keys():
        for item in data.get('data'):#data这个对象非空 并且 这个对象里有叫'data'的key
            yield item.get('article_url')
def get_page_detai(url):
    try:
        response=requests.get(url) #请求url
        if response.status_code==200:
            return response.text
        return None
    except RequestException:
        print('请求异常')
        return None
def parse_page_chirld(htmlchirld,url):
    soup=BeautifulSoup(htmlchirld,'lxml')
    title=soup.select('title')[0].get_text()
    print(title)
    images_pattern=re.compile('gallery: (.*?),\n',re.S)
    result = re.search(images_pattern, htmlchirld)
    if result:#判断是否成功
        data = json.loads(result.group(1))  # 对字符串进行解析,把字符串转化成json对象
        if data and 'sub_images' in data.keys():  # 判断里面是否含有我们想要的数据
            sub_images = data.get('sub_images')
            images_url=[item.get('url') for item in sub_images]
            for image in images_url: download_image(image)
            return {
                'title': title,
                'url': url,
                'images_url': images_url
            }
def download_image(url):
    print('正在下载',url)
    try:
        response=requests.get(url)
        if response.status_code==200:
            #return response.text
            save_image(response.content)#content二进制
        return None
    except RequestException:
        print('请求图片出错',url)
        return None

def save_to_mongo(result):
    if db[MONGO_TABLE].insert(result):
        print('储存mongodb成功',result)
        return True
    return False
def save_image(content):
    file_path='{0}/{1}.{2}'.format('D:\jiepai',md5(content).hexdigest(),'jpg')
    if not os.path.exists(file_path):
        with open(file_path,'wb') as f:
            f.write(content)
            f.close()
def main(offset):
    html=get_page_first(offset,KEYWORD)
    print(html)
    for url in parse_page_first(html):
        htmlchirld=get_page_detai(url)
        if htmlchirld:
            result=parse_page_chirld(htmlchirld,url)
            if result:save_to_mongo(result)

if __name__=='__main__':
    for x in range(GROUP_START,GROUP_END+1):
        main(x*20)
文章被以下专栏收录
21 条评论
推荐阅读