微信号:PythonTZXY

介绍:每天更新,更新python相关的知识.希望诸君有所收获!

Python模拟 Ajax 请求抓取今日头条街拍美图

2019-05-14 20:51 K0rz3n

作者:K0rz3n

原文:

https://www.k0rz3n.com/

1.分析网页确定思路

首先我们打开头条街拍的页面,我们发现我们看到的详细页链接直接在源代码中并不能找到,于是我们就需要去查看我们的 ajax 请求,看看是不是通过 ajax 加载的,我们可以打开浏览器控制台,我们过滤 XHR 请求有了一些发现,如下图:

在 xhr 请求中 offset 为 0 的部分,页面中的 data 为 0 的 数据部分清楚地地显示了我们想要查找的详细页的数据,然后随着我们滚动条的下拉,页面会不断发起 xhr 请求,offset 会随之不断的增大,每次增大的数目为 10 ,实际上是通过 ajax 去请求索引页,每次返回的 json 结果中有10条详细页的数据,这样我们就能不断在页面中获取到街拍新闻的信息。

有了街拍新闻,自然我们还要进入新闻中获取街拍的美图,我们看一下新闻内部的图片是怎么获取的,如下图所示:

很明显,街拍真正的图片的 URL 是通过网页中的 js 变量的方式获取的,我们考虑使用 正则 来获取,另外,页面第一个 title 标签里面有该详细页面的名称,我们可以使用 BeautifulSoup 来提取出来

思路梳理:

(1)使用 requests 库去去请求网站,并获取索引网页(ajax 请求的 url)返回的 json 代码
(2)从索引网页中提取出详细页面的 URL,并进一步抓取详细页的信息
(3)通过正则匹配详细页中的图片链接,并将其下载到本地,并将页面信息和图片的 URL 保存到本地的 MongoDB
(4)对多个索引页进行循环抓取,并开启多线程的方式提高效率

2.代码实现

config.py

MONGO_URL = 'localhost'MONGO_DB = 'toutiao'MONGO_TABLE = 'toutiao'
GROUP_STATR = 0GROUP_END = 5
KEYWORD = '街拍'
IMAGE_DIR = 'DOWNLOADED'

spider.py

import requestsimport refrom bs4 import BeautifulSoupfrom urllib.parse import urlencodeimport jsonfrom requests.exceptions import RequestExceptionfrom config import *import pymongoimport osfrom hashlib import md5from multiprocessing import Pool

# 声明 mongodb 数据库对象client = pymongo.MongoClient(MONGO_URL)db = client[MONGO_DB]


def get_page_index(offset,keyword): data = { 'aid': 24, 'app_name': 'web_search', 'offset': offset, 'format': 'json', 'keyword': keyword, 'autoload': 'true', 'count': 20, 'en_qc': 1, 'cur_tab': 1, 'from': 'search_tab', 'pd': 'synthesis', 'timestamp': 1556970196243, }
headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36', 'Cookie':'...' }
url = 'https://www.toutiao.com/api/search/content/?' + urlencode(data) try: res = requests.get(url,headers=headers) res.encoding = 'utf-8' if res.status_code == 200: return res.text return None except RequestException: print('requests index page error') return None
def parse_page_index(html): data = json.loads(html) if data and 'data' in data.keys(): for item in data.get('data'): yield item.get('article_url')

def get_page_detail(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36', 'Cookie': '...' }
try: res = requests.get(url, headers=headers) res.encoding = 'utf-8' if res.status_code == 200: return res.text return None except RequestException: #print('requests detail page error',url) return None

def parse_page_detail(html,url):
soup = BeautifulSoup(html,'html.parser') title = soup.select('title')[0].get_text() pattern = re.compile("articleInfo: {.*?content: '(.*?);',",re.S) images = re.search(pattern,html) if images: images_pattern = re.compile("&lt;img src&#x3D;&quot;(.*?)&quot; img_width&#x3D;&quot;") res = re.findall(images_pattern,images.group(1)) for image_url in res: dir_name = re.sub(r'[\\\\/:*?|"<> ]','',title) download_image(image_url,dir_name[:10]) return { 'title': title, 'url': url, 'images': res, }

def save_to_mongo(result): if db[MONGO_TABLE].insert(result): print("成功存储到 mongodb 数据库",result) return True return False
def download_image(url,dir_name): print('正在下载:',url) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36', 'Cookie': '...' }
try: res = requests.get(url, headers=headers) if res.status_code == 200: # 存储二进制数据的时候使用content save_image(dir_name,res.content) return None except RequestException: print('requests image error',url) return None
def save_image(dir_name,content):
if not os.path.exists(IMAGE_DIR + '/' + dir_name): os.makedirs(IMAGE_DIR + '/' + dir_name) file_path = '{0}\\{1}\\{2}\\{3}.{4}'.format(os.getcwd(),IMAGE_DIR,dir_name,md5(content).hexdigest(),'jpg') if not os.path.exists(file_path): with open(file_path,'wb') as f: f.write(content)

def main(offset):
html = get_page_index(offset,KEYWORD) #print(html) for url in parse_page_index(html): #print(url) html = get_page_detail(url) if html: result = parse_page_detail(html,url) if result: #print(result) save_to_mongo(result)
if __name__ == '__main__': groups = [x*20 for x in range(GROUP_STATR,GROUP_END + 1)] pool = Pool() pool.map(main,groups)

3.运行效果


 
Python学习交流 更多文章 python+pyqt5实现KFC点餐收银系统 Python-定时爬取指定城市天气:邮件提醒 Python scrapy框架爬取瓜子二手车信息数据 Python爬虫框架Scrapy的爬虫自动登录 Python破解极验滑动验证码
猜您喜欢 程序员,如何摆脱平庸? 沸腾!阿里给程序员送了一份圣诞大礼 百度云智峰会 • 2017深圳大会-数字营销 指针函数和函数指针