1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Python爬虫实战02:分析Ajax请求并抓取今日头条街拍

Python爬虫实战02:分析Ajax请求并抓取今日头条街拍

时间:2023-01-10 06:08:43

相关推荐

Python爬虫实战02:分析Ajax请求并抓取今日头条街拍

1 目标网站分析

首先我们打开今日头条网站,搜索 街拍,点击图集,这里每就是我们要爬取的目录,我们称为索引页。1

点开一个标题,进去,称为详情页。2这里面的图是我们所要爬取的。比如这里可以点击图片,共7张图。2

这里我们可以想到,可以先把详情页的每个标题URL爬取下来,再请求详情页得到每个图集。

分析详情页代码,打开谷歌浏览器开发工具,选择Network,刷新网页。发现第一个请求中返回的不含图片的任何信息。

想到头条应该是Ajax请求,选择XHR,继续刷新,点击图集。发现我们点击图集发出的请求返回的代码中data中含有我们想要的图片信息,是Json格式。可以看到title信息,刚好符合。

3

Headers,属于get请求,可以看到请求参数。

4

也可以看到我们请求索引页的网址。

然后滑动网页,发现左边又多了个请求,offset=20,由此得知索引页可通过改变offset来换页。6

继续看详情页,我们想找到每个图集的内容。同样打开network工具,刷新网页。选择XHR,发现每个请求中都不包含图集信息。选择ALL查看,我们可以看到对应网址的请求返回了一段代码。我们右击图片,新窗口查看,得到图片的地址后面的数字。到前面的代码中搜索,发现图片信息恰好在gallery: JSON.parse(” “)中,是Json格式。其中’sub_image’的值包含的就是我们想要获取的图集的信息。7

理一下基本思路:

爬取索引页的信息。通过分析ajax请求,得到每个详情页的网址。(比如这里就返回了18个详情页)爬取详情页的信息,分析网页代码,用正则表达式得到每个图集的信息。将爬取的信息存到MongoDB,并下载图片。通过改变offset爬取多页信息,利用多线程加快速度。

2 流程框架

抓取索引页内容

利用requests请求目标站点,得到索引网页HTML代码,返回结果。

抓取详情页内容

解析返回结果,得到详情页的链接,并进一步抓取详情页的信息。

下载图片与保存数据库

将下载的图片保存到本地,并把页面信息及图片URL保存至MongDB.

开启循环和多线程

对多页内容遍历,开启多线程提高抓取速度。

3 爬虫实战

使用pycharm。

3.1 抓取索引页内容

def get_page_index(offset, keyword):"""抓取索引页的内容"""data = { # 请求参数,offset和keyword我们设置成变量,方便改变。'offset': offset,'format': 'json','keyword': keyword,'autoload': 'true','count': 20,'cur_tab': 3,'from': 'gallery'}# urlencode()可以把字典对象转化为url的请求参数url = '/search_content/?' + urlencode(data)try: # 防止程序中断response = requests.get(url) if response.status_code == 200: # 如果访问成功则返回文本内容return response.textreturn Noneexcept RequestException:print('请求索引页出错')return None

3.2 解析索引数据

def parse_page_index(html):""" 解析索引数据"""# json.loads()对JSON数据进行解码,转换成一个字典data = json.loads(html)# 当data这个字典存在且'data'键名存在与data字典中。data.keys()返回data这个字典所有的键名if data and 'data' in data.keys():# get() 函数返回字典中指定键的值,在这里遍历data字典中键名为'data'的# 值,每个元素分别为一个图集。for item in data.get('data'):# 对于'data'的值中的每个元素,建立一个生成器,得到每个网址yield item.get('article_url') # 'article_url'中信息是每个图集的网址

3.3 获取详情页信息

def get_page_detail(url):""" 拿到详情页图的信息"""try:# 此处不加headers会导致访问详情页失败headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64;x64)AppleWebKit/537.36(KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'}response = requests.get(url, headers=headers)if response.status_code == 200:return response.textreturn Noneexcept RequestException:print('请求详情页出错', url)return None

3.4 解析详情页

def parse_page_detail(html, url):""" 解析详情页"""# 声明解析后的网页对象soup = BeautifulSoup(html, 'lxml')# 通过传入css选择器,选择第一个<title>标签,获取文本内容,就是图集的标题。title = soup.select('title')[0].get_text()# 声明一个正则表达式对象,来匹配我们想要的Json语句。注意re.S使 . 能匹配任意字符。images_pattern = pile('gallery: JSON.parse\("(.*?)"\),', re.S)result = re.search(images_pattern, html)# 注意:这里的Json语句包含转义字符 \ ,不去掉会报错result = result.group(1).replace('\\', '')# result = re.sub(r'\\', '', result.group(1))if result: # 结果存在则进行data = json.loads(result) # 把Json转换为字典if data and 'sub_images' in data.keys():# 'sub_images'这个键的值是一个列表,里面每个元素是字典,包含每个图集的地址。sub_images = data.get('sub_images') # 得到图集的地址images = [item.get('url') for item in sub_images] # 构造一个图集列表,包含每个图片的地址。for image in images:download_image(image) # 下载每张图片return { # 返回一个字典,格式化数据,准备存入MongoDB'title': title,'url': url,'images': images,}

3.5 定义下载图片函数

def download_image(url): # 传入的是每张图片的地址""" 下载图片"""print('正在下载', url) # 调试信息try:headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36''(KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'}response = requests.get(url, headers=headers)if response.status_code == 200:save_image(response.content) # 保存图片,content返回二进制内容(当保存图片视频时)return Noneexcept RequestException:print('请求图片出错', url)return None

3.6 定义保存图片函数

def save_image(content):"""存图片"""# 定义文件路径,文件名把图片信息md5加密,保证每个文件名不同。file_path = '{0}/{1}.{2}'.format(os.getcwd() +'\images', md5(content).hexdigest(), 'jpg')if not os.path.exists(file_path): # 如果文件不存在with open(file_path, 'wb') as f:f.write(content)'''w以写方式打开,不存在则创建a以追加模式打开 (从 EOF 开始, 必要时创建新文件)r+以读写模式打开w+以读写模式打开 (参见 w )a+以读写模式打开 (参见 a )rb以二进制读模式打开wb以二进制写模式打开 (参见 w )ab以二进制追加模式打开 (参见 a )rb+ 以二进制读写模式打开 (参见 r+ )wb+ 以二进制读写模式打开 (参见 w+ )ab+ 以二进制读写模式打开 (参见 a+ )'''

3.7 存储到数据库

client = pymongo.MongoClient(MONGO_URL)db = client[MONGO_DB]# 其中MONGO_DB,MONGO_URL为配置文件中的参数def save_to_mongo(result):"""存储文件到数据库"""if db[MONGO_DB].insert(result):print('存储成功', result)return Truereturn False

3.8 主函数

def main(offset):""" 主函数"""html = get_page_index(offset, KEYWORD) # 获取索引页网页内容for url in parse_page_index(html): # parse_page_index()返回一个生成器,生成每个图集的地址html = get_page_detail(url) # 得到每个图集详情页的内容if html: # 如果内容返回成功result = parse_page_detail(html, url) # 解析详情页,返回一个字典结果save_to_mongo(result) # 存入数据库

3.9 运行

if __name__ == '__main__':groups = [x * 20 for x in range(GROUP_START, GROUP_END + 1)] # 生成一个offset列表pool = Pool() # 声明一个进程池pool.map(main, groups)pool.close()pool.join()

3.10 头文件

import jsonimport osimport refrom hashlib import md5from multiprocessing import Poolfrom urllib.parse import urlencodeimport pymongoimport requestsfrom bs4 import BeautifulSoupfrom requests.exceptions import RequestExceptionfrom ToutiaoJiepai.config import *

3.11 创建配置文件config.py

# config.pyMONGO_URL = 'localhost'MONGO_DB = 'toutiao'MONGO_TABLE = 'toutiao'GROUP_START = 1GROUP_END = 1KEYWORD = '街拍'

多用if语句的异常语句来保证程序的顺利进行。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。