通过分析Ajax请求抓取今日头条街拍美图
1,首先找到我们要查看的网址
https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D
打开F12 的network 清除所有的请求,再点击'图集' 可以看到

于是我们可以知道此处是通过Ajax请求进行数据的加载的,分析Preview 我们知道返回的数据是json 数据,分析得到我们需要的是article_url 我们要对数据进行处理拿到这个数据,然后对数据进行发送请求拿到我们想要的图片列表
2.当我们拿到连接url后我们对此链接进行访问,我们看到的HTML页面的标签中并没有我们想要的图片列表url
于是我们对页面进行分析(搜索连接后的那串数字,或标题),得到

经分析得到我们要的url列表数据就在这串数据中,因为不是标签中的所以我们要舍弃BeautifulSoup,xpath等,选用正则在获取目标数据
分析之后我们可以拿到文章连接,图片列表连接,之后我们就可以对连接和图片进行保存和下载的操作了,数据比较少就选用脚本进行工作,考虑到scrapy的异步,我们也给脚本使用多线程进行处理
下面开始用代码来完成以上流程
1.获取分析的json数据
#!/usr/bin/env python # _*_ coding:utf-8 _*_ # __author__ jingqi import requests #首先导入requests 库
import urllib #导入urllib 库
headers= {
'x-requested-with': 'XMLHttpRequest',
'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36'
}
def get_page_index(offset, keyword): data = { 'offset': offset, 'format': 'json', 'keyword': keyword, 'autoload': 'true', 'count': '20', 'cur_tab': '3', 'from': 'gallery' } url = 'https://www.toutiao.com/search_content/?' + urllib.urlencode(data) #urllib.urlencode 使用此方法对data数据进行编译
try: #加异常处理
response = requests.get(url,headers=headers) #加上headers 模拟浏览器
if response.status_code == 200: #判断相应状态码
return response.text
else:
return None
except RequestException:
print ('请求失败', url)
return None
2,对返回的数据进行数据得到我们需要的数据
from json import loads
def parse_page_index(content):
data = loads(content) #通过loads方法将json数据转化为python的字典格式的数据
if data and 'data' in data.keys():
for item in data.get('data')[1:]:
yield item.get('article_url')
3.拿到文章连接article_url 发送请求获得返回数据,对数据进行正则匹配获得目标数据
from requests.exceptions import RequestException #导入请求异常 def get_page_detail(url): ''' 对请求状态码进行判断,对数据进行异常处理,返回页面数据 ''' try: response = requests.get(url, headers=headers) if response.status_code == 200: return response.text else: return None except RequestException: print ('请求详情失败',url) return None
4,拿到页面数据进行正则匹配获得目标数据
from bs4 import BeautifulSoup as bs #导入库并起别名 def parse_page_detail(html, url): soup = bs(html, 'lxml') title = soup.select('title') #css 选择器 reg = re.compile('gallery:(.*?)\n', re.S) #re.S 表示全文匹配 result = re.findall(reg, html) # print result, url try: cons = result[0].replace('JSON.parse', '').encode('utf-8') #将Unicode装换为utf-8的string if cons and 'sub_images' in cons: url_list = loads(eval(cons)[0])['sub_images'] #用eval方法将字符串转化为字典 images = [item.get('url') for item in url_list] #print images for image in images: download_image(image) return { 'title': title, 'images': images, 'url': url, } except Exception: pass
以上就是获取到街拍图片列表连接
下面附上完整代码
#!/usr/bin/env python # _*_ coding:utf-8 _*_ # __author__ jingqi import requests from requests.exceptions import RequestException import re import urllib from json import loads import os import hashlib import pymongo from multiprocessing.dummy import Pool #开启多进程引入进程池 from config import * '''
创建Mongo对象
''' client = pymongo.MongoClient(MONGO_URL, MONGO_PORT) db = client[MONGO_DB] headers = { 'x-requested-with': 'XMLHttpRequest', 'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36' } def get_page_index(offset, keyword): data = { 'offset': offset, 'format': 'json', 'keyword': keyword, 'autoload': 'true', 'count': '20', 'cur_tab': '3', 'from': 'gallery' } url = 'https://www.toutiao.com/search_content/?' + urllib.urlencode(data) try: response = requests.get(url,headers=headers) if response.status_code == 200:return response.text else: return None except RequestException: print ('请求失败', url) return None def parse_page_index(content): data = loads(content) if data and 'data' in data.keys(): for item in data.get('data')[1:]: yield item.get('article_url') def get_page_detail(url): try: response = requests.get(url, headers=headers) if response.status_code == 200: return response.text #result = parse_page_detail(response.content, url) else: return None except RequestException: print ('请求详情失败',url) return None def parse_page_detail(html, url): #soup = bs(html, 'lxml') #title = soup.select('title') #print title reg = re.compile('gallery:(.*?)\n', re.S) result = re.findall(reg, html) # print result, url try: cons = result[0].replace('JSON.parse', '').encode('utf-8') #将Unicode装换为utf-8的string if cons and 'sub_images' in cons: url_list = loads(eval(cons)[0])['sub_images'] #用eval方法将字符串转化为字典 images = [item.get('url') for item in url_list] #print images for image in images: download_image(image) return { ##'title': title, 'images': images, 'url': url, } except Exception: pass def download_image(url): try: response = requests.get(url, headers=headers) if response.status_code == 200: save_image(response.content, url) #return response.text else: return None except RequestException: print ('请求图片详情失败',url) return None def save_image(content,url): print '正在下载',url file_path = '{0}/{1}.{2}'.format(os.getcwd(), hashlib.md5(content).hexdigest(), 'jpg') #os.getcwd()当前位置,
if not os.path.exists(file_path):
with open(file_path, 'wb') as f:
f.write(content)
f.close()
def save_to_mongo(result):
print '正在准备存储到MongoDB中'
print result
if db[MONGO_TABLE].insert(result):
print '正在存储到MongoDB中',result
return True
return False
def main(offset):
html = get_page_index(offset, KEYWORD)
for url in parse_page_index(html):
html = get_page_detail(url)
if html:
result = parse_page_detail(html, url)
if result is None:
print 'result is None'
else: save_to_mongo(result)
if __name__ == '__main__':
main(0)
groups = [ x*20 for x in range(GROUP_START,GROUP_END + 1) ] #生成一个列表
pool = Pool() #使用多进程
pool.map(main, groups)
下面是配置文件
#!/usr/bin/env python # _*_ coding:utf-8 _*_ # __author__ jingqi MONGO_URL = 'localhost' MONGO_PORT = 27017 MONGO_DB = 'toutiao' MONGO_TABLE = 'toutiao' GROUP_START = 1 GROUP_END = 20 KEYWORD = '街拍'
展示部分图片

部分mongo中数据展示


浙公网安备 33010602011771号