跟着某乎玩python(二)

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

本篇“玩python”来源答主链接:

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

相似参考博文链接:

python 分析Ajax来抓取今日头条街拍美图
python爬虫—— 抓取今日头条的街拍的妹子图

环境配置:

1.系统环境:Ubuntu 14.04 LTS
2.编译环境:Python3.4.3
3.依赖库: requests pymongo BeautifulSoup re json multiprocessing
4.其他工具:Chrome浏览器

网页分析

首先使用Chrome浏览器打开要爬取的网页
1.搜索框内查找网页
2.进入目的网页点击右键–检查
3.找到所用信息

鼠标选定的那个就是其中一页索引页,一共加载了四页。
  我们可以看到 四个索引页之间的区别只有 offset参数有区别,其他都是一模一样的。
  如此来说我们就可以通过修改offset参数来获取任意索引页了。
    第一页索引页 offset = 0
    第二页索引页 offset = 20
    第三页索引页 offset = 40
    第四页索引页 offset = 60
  由此可以看出 offset的规律是 跨步20递增。

代码浅析

流程图

Created with Raphaël 2.1.0 抓取首页 抓取详情页解析 下载图片 存入数据库 结束 Error yes no yes no yes no

配置文件config

首先得把config.py文件了解清楚,该文件的目的有两个:
- 其一:配置mongoDB数据库相关的内容
- 其二:配置下载页数及关键词KEYWORD

MONGO_URL ='localhost'
MONGO_DB = 'toutiao'
MONGO_TABLE = 'toutiao'

GROUP_START = 1
GROUP_END = 2
KEYWORD = '模特'

注意:
记得导入该文件:from config import *
第一次导入时,会自动生成一个名为__pycache__文件夹,该文件里含有config.cpython-34.pyc,是一个二进制文件,百度可知其作用是:下次再导入时速度会很快。暂时理解为缓冲器,未作深究。

抓取首页

def get_page_first(offest,keyword):#抓取首页
    data={
        'offset':offest,  #offest可变
        'format':'json',
        'keyword':keyword,#keyword是可以从config,py文件中定义
        '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

调用requests的get方法得到网页,状态码200代表请求正常请求成功。

分析首页

def parse_page_first(html):
    data=json.loads(html)#转换成json对象
    if data and 'data' in data.keys():
        for item in data.get('data'):#data这个对象非空 并且存在key为'data'数据
            yield item.get('article_url')

这里要说明一下,可能data多次出现会导致混乱,注释里已经注明。‘data’即这个单引号括起来的data,是Json对象data里的一个Key值为‘data’的数据,这里面放着什么呢?在Chrome浏览器“检查”分析的时候会看到,这里面存在着我们想要的数据,title(标题)、image_list(存放图片链接的列表)等等。yield生成器不再赘述,可参看上一篇里的菜鸟教程的链接。

抓取详情页

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

分析详情页

def parse_page_chirld(htmlchirld,url):
    soup=BeautifulSoup(htmlchirld,'lxml')
    title=soup.select('title')[0].get_text()
    print(title)
#    print(htmlchirld)
    images_pattern=re.compile('gallery: (.*?),\n',re.S)
    result = re.search(images_pattern, htmlchirld)
    if result:
        result = result.group(1)
#       print(result) #log1
        result = result[12:]
        result = result[:-2]
        result = re.sub(r'\\','',result)
#        print(result) #log2
        data = json.loads(result)  
        print(data)
        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
            }

log1与log2调试时添加,其中的几行代码也是添加的,关于代码中re正常匹配请参考菜鸟教程python3正则部分。为什么去匹配”gallery”?匹配返回的是:
<_sre.SRE_Match object; span=(4521, 8184), match='gallery: JSON.parse("{\\"count\\":5,\\"sub_images>
而再调用group(1)会得到一个不标准无法直接JSON解析的<class str>,于是就有手动切片处理字符串,去除字符“\”的一系列操作。

下载图片

def download_image(url):
    print('正在下载',url)
    try:
        response=requests.get(url)
        if response.status_code==200:
            save_image(response.content)#content二进制
        return None
    except RequestException:
        print('请求图片出错',url)
        return None

def save_image(content):
    file_path='{0}/{1}.{2}'.format('./',md5(content).hexdigest(),'jpg')
    if not os.path.exists(file_path):
        with open(file_path,'wb') as f:
            f.write(content)
            f.close() 

这部分很简单,陌生的hashlib的md5加密算法。
md5(content).hexdigest()
上面这个调用返回的是一个真正的哈希码,即这种形式:9d5e54f12f3f4a8b6dd02439b1a3da144ce20e89

存入数据库

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

单单上面几行代码还无法完成将result这个dict存入数据库的操作,还需要:

1.config配置正确无误
2.在代码执行到的地方加入
client=pymongo.MongoClient(MONGO_URL)
db=client[MONGO_DB]

完整代码点这里

效果


查看数据库择需要命令:
mongo
use toutiao
db.toutiao.find().pretty()

回顾与思考

  • 多线程的优势慢慢显露,下载更快。
  • MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
  • MongoDB将数据存储为一个文档,数据结构由键值(key=>value)对组成。
  • MongoDB文档类似于JSON对象。字段值可以包含其他文档,数组及文档数组。
  • Ajax是一种动态更新网页界面的技术。即:AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
  • 可以尝试导入argv将代码写成带参数的脚本形式,配置文件内容写进脚本,参数是关键词等等。

猜你喜欢

转载自blog.csdn.net/qq_30650153/article/details/78650834