Ajax
AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。
AJAX 是一种用于创建快速动态网页的技术。
通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
传统的网页(不使用 AJAX)如果需要更新内容,必须重载整个网页页面(html页面)。
例如
往下拉进度条,这个显示加载中的样式就是Ajax异步加载。
流程框架
- 分析Ajax的网页
- 分析街头美拍详细页面的网页组成
- 分析索引页内容
- 下载图片及保存数据库
- 开启循环和多进程
分析Ajax的网页
我们查看网页审查,分析Ajax加载的秘密。
首先动态加载肯定不是Doc目录下的,所以应该在XHR下查找。
根据观察以及往下拉网页我们会发现有一个?offset这个标签一直在刷新,而且每次都会增加偏移量20。然后我们找到Preview查找到响应的代码,在data标签下包含图片和标题。
分析街头美拍详细页面的网页组成
网页组成上面基本已经分析了,下面先看代码。
首先获取详情页的html页面
#根据url获取详情页的html页面
def get_detail_html(url):
try:
res = requests.get(url)
if res.status_code != 200:
print('请求详情页失败')
return None
print('请求详情页成功')
html = res.text
return html
except RequestException:
print('异常发生请求失败')
return None
根据获取到的html解析有用数据
#根据html文件 抓取标题和urls
def parse_html(html):
soup = BeautifulSoup(html, 'lxml')
title = soup.select('title')[0].get_text() #标题在 title标签下 直接获取即可
print(title)
#这个含有urls的json语句 位于 var gallery = 这个之后,所以我们做一个匹配
pattern = re.compile(' var gallery = (.*?);')
result = re.search(pattern, html)
if result:
# 该json包含2个元素
# coust : 7
# sub_images : url的list 这是我们需要查找的 这里面还包含了一个字典
data = json.loads(result.group(1))
# 查找sub_images是否存在
if data and 'sub_images' in data.keys():
sub_images = data.get('sub_images') #获取这个列表
#获取所有键值为url的 values
#images = [item['url'] for item in sub_images]
images = [item.get('url') for item in sub_images]
#每一张图片的url 传入 获取下载
[download_image(url) for url in images]
#将这一组信息传出去
return {
'title' : title,
'urls' : images
}
在其中每次解析到了图片url我们可以选择下载
#下载url对应的 html文件
def download_image(url):
try:
res = requests.get(url)
if res.status_code != 200:
print('下载失败')
return None
print('开始下载...')
save_image(res.content) #二进制文本文件
except RequestException:
print('异常发生下载失败')
return None
将下载的图片保存到本地
#将二进制信息保存到本地 也就是图片
def save_image(content):
file_path = '{0}/{1}.{2}'.format(os.getcwd() + '/image',md5(content).hexdigest(), 'jpg')
if not os.path.exists(file_path):
with open(file_path, 'wb') as f:
f.write(content)
f.close()
我们即可得到以下打印信息
请求详情页成功
路人街拍,街拍女孩儿的牛仔裤特辑
开始下载...
开始下载...
开始下载...
开始下载...
开始下载...
开始下载...
开始下载...
{'title': '路人街拍,街拍女孩儿的牛仔裤特辑', 'urls': ['http://p3.pstatp.com/origin/22d1000035dd9b85559d',
...']}
在项目的image文件夹下也包含下载的图片。
分析索引页内容
索引页的一个url包含一个图集,一个图集下包含很多图片。
#获取索引页内容 他是一个json格式的
#内容依旧是在 data下 包含标题和详情页url
def get_index_page(offset, keyword):
header = {
'offset': offset,
'format': 'json',
'keyword': keyword,
'autoload': 'true',
'count': '20',
'cur_tab': '1'
}
#例如第一个url是:
# http://www.toutiao.com/search_content/?offset=0&format=json&keyword=%E8%A1%97%E6%8B%8D&autoload=true&count=20&cur_tab=1
url = 'http://www.toutiao.com/search_content/?' + urlencode(header)
try:
res = requests.get(url)
if res.status_code != 200:
print('请求索引页失败')
return None
print('请求索引页成功')
return res.text
except RequestException:
print('发生异常请求索引页失败')
return None
获取到了整个索引页的html之后(注意这只是一次Ajax加载出现的内容,如需多次加载需要修改offset)需要即解析内容。
#获取索引页 某一次加载的全部 图集的标题和urls 这个urls即可进入详情页
def parse_index_html(html):
jd = json.loads(html)
data = jd['data']
urls = [item['url'] for item in data]
titles = [item['title'] for item in data]
#当然也直接可以组成一个生成器,这样就可以直接使用for
return dict(zip(titles, urls)) #组成字典返回
调用如下
def main():
html = get_index_page('0', '街拍')
for title,url in parse_index_html(html).items():
detail_html = get_detail_html(url)
print(parse_html(detail_html))
然后运行就可以在images目录下看到一堆图片了。
下载图片及保存数据库
下载图片上面已经提到了。
接下来试着分析数据以及保存数据。
数据分析模块,python有一个强大的第三方库那就是pandas。
Python Data Analysis Library 或 pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便捷地处理数据的函数和方法。你很快就会发现,它是使Python成为强大而高效的数据分析环境的重要因素之一。
保存方法
#为了将title和 urls组成一个list
#这个list包含2个参数 title 和 url的列表
def to_list(title, urls):
return [title, str(urls)]
#保存到数据库
def save_to_sql(lst):
#传入一个list参数
df = pandas.DataFrame(lst)
df.to_excel('urls.xlsx') #转换成Excel
#存储到sql
with sqlite3.connect('urls.sqlite') as db:
df.to_sql('urls', con=db)
调用方式
def main():
html = get_index_page('0', '街拍')
lst = []
for title,url in parse_index_html(html).items():
detail_html = get_detail_html(url)
dic = parse_html(detail_html)
if dic is not None:
lst.append(to_list(title, dic['urls']))
save_to_sql(lst)
可以看到我们将所有的title和url列表 共同组成一个列表lst传入 save_to_sql以便保存这些数据。
运行之后我们可以查看我们的sql数据库和Excel表
开启循环和多进程
上述运行其实还是一个进程,速度也略慢。我们可以使用进程池加快速度!
这时我们需要给main一个参数,让不同的进程运行
def main(offset):
html = get_index_page(str(offset), '街拍')
lst = []
for title,url in parse_index_html(html).items():
detail_html = get_detail_html(url)
dic = parse_html(detail_html)
if dic is not None:
lst.append(to_list(title, dic['urls']))
save_to_sql(lst)
if __name__ == '__main__':
pool = Pool()
#因为url每次的偏移量为20
pool.map(main, [x*20 for x in range(0,10+1)])
全部完成!
另外注意数据库存在了需要增加判断。。。以免重复创建而报错