python 爬虫抓取今日头条街拍图片

1. 打开google浏览器,输入www.toutiao.com, 搜索街拍。

2.打开开发者选项,network监看加载的xhr, 数据是ajax异步加载的,可以看到preview里面的data数据

3.下拉刷新查看加载的offset,每次加载20条数据,data是json数据,里面的article_url,是图集详情页的url。

4.首先抓取索引页的内容

  data数据来自于索引页的请求都里面的query str

 1 # 提取索引页的数据
 2 def get_page_index(offset, keyword):
 3     data = {
 4         'offset': offset,
 5         'format': 'json',
 6         'keyword': keyword,
 7         'autoload': 'true',
 8         'count': 20,
 9         'cur_tab': 1
10     }
11     # 向路由中出入参数, 构建完整url
12     url = 'http://www.toutiao.com/search_content/?' + urlencode(data)
13     try:
14         response = requests.get(url)
15         if response.status_code == 200:
16             return response.text
17         return None
18     except RequestException:
19         print('请求索引页出错')
20         return None

5. 接下来是解析索引页的数据,提取出所需要的详情页的url,索引页的data是json数据,里面的article_url,是图集详情页的url。

 1 # 解析索引页的json数据(Preview),并提取详情页url
 2 def parse_page_index(html):
 3     try:
 4         data = json.loads(html)
 5         if data and 'data' in data.keys():
 6             for item in data.get('data'):
 7                 # 用生成器的方式,惰性获取详情页的url
 8                 yield item.get('article_url')
 9     except JSONDecodeError:
10         pass

6. 有了详情页的url,接下来就是获取详情页的数据和代码了

 1 # 获取详情页面的数据代码
 2 def get_page_detail(url):
 3     try:
 4         response = requests.get(url, timeout=5)
 5         if response.status_code == 200:
 6             return response.text
 7         return None
 8     except RequestException:
 9         print('请求详情页出错', url)
10         return None

7. 接着就是解析详情页面,并提取title, 和图片url, 详情页代码数据在Doc中查看, 注意提取的是组图,非组图被过滤了.url_list 是指三个地址都是图片的地址,我们只要有一个原始的url就可以了。
  以某个详情页为例,在浏览器中输入http://www.toutiao.com/a6473742013958193678/。开发者选项,network, Doc

 1 # 解析详情页面并提取title, 和图片url
 2 def parse_page_detail(html, url):
 3     soup = BeautifulSoup(html, 'lxml')
 4     title = soup.select('title')[0].get_text()
 5     print(title)
 6     images_pattern = re.compile(r'gallery: (.*?),\n')
 7     result = re.search(images_pattern, html)
 8     if result:
 9         # 将json数据转换为python的字典对象
10         data = json.loads(result.group(1))
11         if data and 'sub_images' in data.keys():
12             sub_images = data.get('sub_images')
13             images = [item.get('url') for item in sub_images]
14             for image in images: download_image(image)
         # 返回标题,此详情页的url,和图片url列表
15 return { 16 'title': title, 17 'url': url, 18 'images': images 19 }

8. 把解析提取的数据存储到mongodb中,以字典的方式.

  先写个mongo的配置文件config.py

1 MONGO_URL = 'localhost'
2 MONGO_DB = 'toutiao'
3 MONGO_TABLE = 'toutiao'
4 
5 GROUP_START = 0
6 GROUP_END = 20
7 
8 KEYWORD = '街拍'

  然后连接本地mongo,存储数据

1 client = pymongo.MongoClient(MONGO_URL, connect=False) # connect=False防止多线程在后台多次连接mongo数据库
2 db = client[MONGO_DB]
3 
4 # 把详情页面的url和标题(title)以及组图的地址list保存到mongo中
5 def save_to_mongo(result):
6     if db[MONGO_TABLE].insert(result):
7         print('存储到MongoDB成功', result)
8         return True
9     return False

9. 下载图片

 1 # 下载图数据,并保存图片
 2 def download_image(url):
 3     print('正在下载', url)
 4     try:
 5         response = requests.get(url)
 6         if response.status_code == 200:
 7             # response.content 为二进制数据
 8             save_image(response.content)
 9         return None
10     except RequestException:
11         print('请求图片失败', url)
12         return None
13 
14 
15 # 保存图片
16 def save_image(content):
17     # 使用md5生成加密名字,同时防止相同的图片重复下载
18     file_path = '{0}/{1}.{2}'.format(os.getcwd(), md5(content).hexdigest(), 'jpg')
19     if not os.path.exists(file_path):
20         with open(file_path, 'wb') as f:
21             f.write(content)

10. 爬虫主函数

1 def main(offset):
2     html = get_page_index(offset, KEYWORD)
3     for url in parse_page_index(html):
4         html = get_page_detail(url)
5         if html:
6             result = parse_page_detail(html, url)
7             if result: save_to_mongo(result)

11. 开启多进程

1 if __name__ == '__main__':
2     groups = [x * 20 for x in range(GROUP_START, GROUP_END)]
3     pool = Pool()
4     pool.map(main, groups)

12. 需要的库函数

 1 import requests
 2 import re
 3 import pymongo
 4 from urllib.parse import urlencode
 5 from requests.exceptions import RequestException
 6 from json.decoder import JSONDecodeError
 7 from bs4 import BeautifulSoup
 8 import json
 9 import os
10 from hashlib import md5
11 from config import *
12 from multiprocessing import Pool

 

 完整代码: https://github.com/huazhicai/Spider/tree/master/jiepai

posted @ 2017-10-07 11:53  华之菜  阅读(2458)  评论(0编辑  收藏  举报