目标网站分析
1、目标网站分析
进入头条网站,关键字搜索:街拍,出现的页面称为 索引页,如下:
上图中的Request URL为请求地址,取出其中的部分信息
https://www.toutiao.com/search_content/?
与下图中的请求头参数拼接,用于构造url.
通过不断向下拉动滚动条,发现请求的参数中offset一直在变化(每次增加20),所以每次请求通过offset来控制新的ajax请求。
2、通过ajax请求获取索引页面
'''
获取索引页
'''
def get_page_index(offset, keyword):
data = {
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': '20',
'cur_tab': '1',
'from': 'search_tab'
}
# urlencode()可以将字典对象转化为url的请求参数
url = 'https://www.toutiao.com/search_content/?' + urlencode(data)
try:
response = requests.get(url)
# print(response.status_code)
if response.status_code == 200:
return response.text
return None
except RequestException:
print("请求索引页出错")
return None
解析ajax请求索引页的返回结果
'''
解析ajax请求索引页返回的结果
'''
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')
基本思路:
- 爬取索引页的信息。通过分析ajax请求,得到每个详情页的网址。(比如这里就返回了18个详情页)
- 爬取详情页的信息,分析网页代码,用正则表达式得到每个图集的信息。
- 将爬取的信息存到MongoDB,并下载图片。
- 通过改变offset爬取多页信息,利用多线程加快速度。
流程框架
-
抓取索引页内容
利用requests请求目标站点,得到索引网页HTML代码,返回结果。
-
抓取详情页内容
解析返回结果,得到详情页的链接,并进一步抓取详情页的信息。
-
下载图片与保存数据库
将下载的图片保存到本地,并把页面信息及图片URL保存至MongDB.
-
开启循环和多线程
对多页内容遍历,开启多线程提高抓取速度。
代码:
# -*- coding: utf-8 -*-
import os
import re
from _md5 import md5
import requests
from urllib.parse import urlencode
from requests.exceptions import RequestException
import json
from multiprocessing import Pool
import pymongo
from bs4 import BeautifulSoup
MONGO_URL = 'localhost' # 数据库地址
MONGO_DB = 'toutiao' # 数据库名称
MONGO_TABLE = 'toutiao' # 数据库表
GROUP_START = 1 # 组图开始组别
GROUP_END = 20 # 组图结束组别
KEYWORD = '街拍' # 关键词
client = pymongo.MongoClient(MONGO_URL) # 连接MongoDB
db = client[MONGO_DB] # 如果已经存在连接,否则创建数据库
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
}
'''
获取索引页
'''
def get_page_index(offset, keyword):
data = {
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': '20',
'cur_tab': '1',
'from': 'search_tab'
}
# urlencode()可以将字典对象转化为url的请求参数, 拼接得到索引页的url
url = 'https://www.toutiao.com/search_content/?' + urlencode(data)
try:
response = requests.get(url, headers=headers)
# print(response.status_code)
if response.status_code == 200:
return response.text
return None
except RequestException:
print("请求索引页出错")
return None
'''
解析ajax请求索引页返回的结果
'''
def parse_page_index(html):
data = json.loads(html) # 反序列化json字符串
if data and 'data' in data.keys():
for item in data.get('data'):
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 # 返回html文本
return None
except RequestException:
print("请求详情页出错", url)
return None
'''
下载图片
'''
def download_image(url):
print("正在下载", url)
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
print("即将保存图片")
save_image(response.content) # 保存二进制流为图片
else:
return None
except RequestException:
print("下载图片错误", url)
return None
'''
保存图片
'''
def save_image(content):
# if not os.path.exists('images'): # 若不存在图片文件夹则新建
# os.mkdir('images')
# # 第一个参数是当前路径,第二个参数是去除重复图片,第三个参数是图片的格式
# file_path = '{0}/images/{1}.{2}'.format(os.getcwd(),md5(content).hexdigest(),'jpg')
# os.getcwd()获取当前文件路径,用md5命名,保证不重复
file_path = '{}/images/{}.{}'.format(os.getcwd(), md5(content).hexdigest(), 'jpg')
if not os.path.exists(file_path):
with open(file_path, 'wb') as f:
f.write(content)
f.close()
print("图片保存成功")
else:
print("图片已经存在")
'''
解析详情页面信息
'''
def parse_page_detail(html, url):
# soup = BeautifulSoup(html, 'lxml')
# title = soup.select('title')
# # print(title)
# if title:
# title = title[0].get_text()
images_pattern = re.compile('articleInfo:.*?title:\'(.*?)\'.*?content.*?\'', re.S) # .*?匹配任意字符
result = re.search(images_pattern, html)
if result:
title = result.group(1)
url_pattern = re.compile('"(http:.*?)"')
image_url = re.findall(url_pattern, str(result.group(2)))
if image_url:
for image in image_url:
download_image(image) # 下载图片
data = {
'title': title,
'url': url,
'images': image_url
}
return data
'''
将图片存入MONGO数据库
'''
def save_to_mongo(result):
if result:
if db[MONGO_TABLE].insert(result): # 向数据库表中插入数据
print("存储成功", result)
return True
else:
print("存储失败")
return False
def main(offset):
html = get_page_index(offset, KEYWORD)
# print(html)
for url in parse_page_index(html):
html = get_page_detail(url)
# save_txt(html) #保存到txt文件中
print("==================================")
print(url)
# print(html)
if html:
print("准备解析详细页面")
result = parse_page_detail(html, url)
print("即将存储新词到数据库中")
save_to_mongo(result)
# print('result = ', result)
if __name__ == '__main__':
groups = [i * 20 for i in range(GROUP_START, GROUP_END + 1)]
pool = Pool()
pool.map(main, groups)
参考资料:
崔庆才 Python3爬虫
https://www.cnblogs.com/felixwang2/p/8729247.html
https://blog.youkuaiyun.com/Cowry5/article/details/79749925