博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python3编写网络爬虫13-Ajax数据爬取
阅读量:7028 次
发布时间:2019-06-28

本文共 7410 字,大约阅读时间需要 24 分钟。

一、Ajax数据爬取

1. 简介:Ajax 全称Asynchronous JavaScript and XML 异步的Javascript和XML。

它不是一门编程语言,而是利用JavaScript在保证页面不被刷新,页面链接不改变的情况下与服务器交换数据,
获得数据后,再利用JavaScript改变页面。

示例:新浪微博 热门

2. 基本原理

2.1 发送请求

JavaScript可以实现页面交互功能 Ajax也不例外 它是由JavaScript实现的,实际上执行了如下代码

var xmlhttp;if(window.XMLHttpRequest){  # code for IE7+,Firefox,Chrome,Opera,Safari  xmlhttp = new XMLHttpRequest();#新建对象}else{#code for IE6,IE5  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");}xmlhttp.onreadystatechange = function(){#设置监听  if(xmlhttp.readyState==4 && xmlhttp.status==200){    document.getElementById("myDiv").innerHTML = xmlhttp.responseText;  }}xmlhttp.open("POST","/ajax/",true);xmlhttp.send();#发送请求

 

这是javascript对ajax最底层的实现,新建XMLHttpRequest对象 调用onreadystatechange属性设置监听

调用open和send方法发送请求。

之前用python发送请求可以得到响应结果 但这里的请求发送变成了javascript来完成,

由于设置了监听 服务器响应结果时,onreadystatechange属性会被触发 然后解析里面的内容。

2.2 解析内容

得到响应内容后,onreadystatechange属性对应的方法便会触发,利用xmlhttp的responseText属性接收。

类似python中利用requests向服务器发送请求 然后得到响应结果的过程。
返回的结果可能是HTML 也可能是JSON 只需要在js中做进一步处理 例如返回json 可以进行解析和转化。

2.3 渲染页面

js有改变网页内容的能力,解析完响应内容后 调用js里面document.getElementById().innerHTML 改变某个元素内的源代码

这样网页的内容就改变了 简称DOM操作

2.4 总结 3个步骤都是js完成的 微博下拉实际上就是js向服务器发送一个Ajax请求 然后获取服务器响应内容

解析并渲染到网页中。真实数据都是js一次次ajax请求得到的。
如果需要抓取数据 就要知道 请求怎么发送的? 发送到哪里?发送了哪些参数?

3. Ajax分析方法

3.1 查看方法

测试地址:

https://m.weibo.cn/u/1195242865

浏览器开发者工具 ajax请求类型为xhr
Request Headers信息为 X-Requested-With: XMLHttpRequest 标记此请求为Ajax请求

3.2 过滤请求

点击开发者工具Network -> XHR 过滤为ajax请求 不断滑动页面 出现新的请求

发送请求地址:

https://m.weibo.cn/api/container/getIndex?type=uid&value=1195242865&containerid=1076031195242865&since_id=4311085060664535

参数:

type: uid
value: 1195242865
containerid: 1076031195242865
page:1

4. 提取结果

from urllib.parse import urlencodeimport requestsfrom pyquery import PyQuery as pqbase_url = 'https://m.weibo.cn/api/container/getIndex?'#请求url的前半部分headers = {  'Host':'m.weibo.cn',  'Referer': 'https://m.weibo.cn/u/1195242865',  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36',  'X-Requested-With': 'XMLHttpRequest',}# 构造url 发送请求def get_page(page):  params = {    'type': 'uid',    'value': '1195242865',    'containerid': '1076031195242865',    'page':page,  }  url = base_url + urlencode(params)  try:    response = requests.get(url,headers=headers)    if response.status_code == 200:      return response.json()  except requests.ConnectionError as e:    print('Error',e.args)#解析方法 提取id 正文 赞数 评论数 转发数 遍历cards 获取mblog中的各个信息def parse_page(json):  if json:    items = json.get('data').get('cards')    for item in items:    # print(item)    item = item.get('mblog')    if item:      weibo = {} #定义空字典接收数据      weibo['id'] = item.get('id')      weibo['text'] = pq(item.get('text')).text()      weibo['attitudes'] = item.get('attitudes_count')      weibo['comments'] = item.get('comments_count')      weibo['reposts'] = item.get('reposts_count')      yield weibo#遍历page 一共10页 将提取到的结果打印输出if __name__ == '__main__':  for page in range(1,3):    json = get_page(page)    results = parse_page(json)    for result in results:      print(result)

5. 添加到mongodb数据库中

from pymongo import MongoClientclient = MongoClient()db = client['weibo']collection = db['weibo']def save_to_mongo(result):  if collection.insert(result):    print('Saved to Mongo')

 

查看mongo内容

启动mongo服务 查看库 show dbs; 查看当前在哪个库 db.getName(); 进入库 use dbname;

查看数据 db.dbname.find(); 删除当前所在库 db.dropDatabase();

至此分析模拟Ajax请求爬取微博列表完成 爬取结果不重要 还有好多地方可以完善 比如动态计算页码,查看微博全文等等。
主要是让大家了解抓取原理

 

实例:爬取今日头条街拍图片

地址:http://www.toutiao.com 关键字 :街拍

offset: 0format: jsonkeyword: 街拍autoload: truecount: 20cur_tab: 1from: search_tabpd: synthesis

基本代码

import requestsimport jsonimport timeimport reimport osfrom random import choicefrom hashlib import md5url = "https://www.toutiao.com/search_content/?"header = {  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36',}keyword = '街拍'has_gallery_lists = []no_gallery_lists = []def SearchPageParser(offset=0):  payload = {    'offset': offset,    'format': 'json',    'keyword': keyword,    'autoload': 'true',    'count': 30,    'cur_tab': 1,    'from': 'search_tab'  }  count = 0  try:    response = requests.get(url, headers=header, params=payload)    content = None    #打印拼接请求后的url    # print("Parser " + response.url)    if response.status_code == requests.codes.ok:      content = response.text      data = json.loads(content)      if not data:        return      for article in data.get('data'):        if True == article.get('has_gallery') and True == article.get('has_image'):          has_gallery_lists.append(article.get('article_url'))          count += 1        if False == article.get('has_gallery') and True == article.get('has_image'):          no_gallery_lists.append(article.get('article_url'))          count += 1        return count   except Exception as e:    print(e)    return#保存本地函数def SaveImage(imageURL,title):#判断文件夹是否存在  if not os.path.exists(title):    os.mkdir(title)  try:    response = requests.get(imageURL)    if response.status_code == 200:      file_path = '{0}/{1}.{2}'.format(title, md5(response.content).hexdigest(), 'jpg')      # 判断是否重名      if not os.path.exists(file_path):        with open(file_path,'wb') as f:        f.write(response.content)      else:        print('Already Downloaded',file_path)  except:    print('Failed to Save Image')#第一种页面def HasGalleryParser():  if 0 == len(has_gallery_lists):    return  # 正则  pattern = re.compile('gallery: JSON\.parse\("(.*?)max_img', re.S)  pattern_t = re.compile('(.*?)', re.S)  while has_gallery_lists:    this = has_gallery_lists.pop()  try:    response = requests.get(this, headers=header)    content = None    if response.status_code == requests.codes.ok:      content = response.text      data = pattern.findall(content)      pattern_t.findall(content)      if data:      #去掉多余符号        data = data[0][:-4].replace('\\', '') + ']}'        img_urls = json.loads(data).get('sub_images')        title = "".join(pattern_t.findall(content))        for img_url in img_urls:        #保存函数          SaveImage(img_url.get('url'),title)      else:        print("BadPageURL[GalleryParser, {0:s}]".format(this))  except Exception as e:    print(e)    return  time.sleep(0.25)#第二种页面def NoGalleryParser():  if 0 == len(no_gallery_lists):    return  while no_gallery_lists:    this = no_gallery_lists.pop()    #正则匹配    pattern = re.compile('<img src="(.*?)"', re.S)    pattern_t = re.compile('(.*?)',re.S)    try:      response = requests.get(this, headers=header)      content = None      if response.status_code == requests.codes.ok:        content = response.text        img_urls = pattern.findall(content)        img_title = "".join(pattern_t.findall(content))        if img_urls:          for img_url in img_urls:            #保存函数            SaveImage(img_url,img_title)        else:          # 过滤地址          print("BadPageURL[NoGalleryParser, {0:s}]".format(this))    except Exception as e:      print(e)      return  time.sleep(0.25)if __name__ == "__main__":  #计数变量  x, count = 0, 0  # 获取头条页面  cnt_urls = SearchPageParser(x)  while count < 20 and cnt_urls:    cnt_urls = SearchPageParser(x + 20)    count += cnt_urls    x += 20    time.sleep(0.55)    #打印分页地址    # print("Get {0:d} URL(s) in total.".format(count))  # 分析页面  HasGalleryParser()  NoGalleryParser()

 

转载于:https://www.cnblogs.com/liuxiaosong/p/10363894.html

你可能感兴趣的文章
小猿圈python之九九乘法表、金字塔和杨辉三角
查看>>
说说如何使用 vue-router 插件
查看>>
警告忽略
查看>>
Java Bean + 注册验证
查看>>
通过mysql 插入一句话***
查看>>
centos 分区扩容
查看>>
JBoss EAP 6 monitoring using remoting-jmx and Zabbix
查看>>
邮件服务器
查看>>
OOAD-设计模式-原型模式
查看>>
Java FAQ(2)
查看>>
JavaScript常用事件总结
查看>>
squid在企业网中的应用
查看>>
主元素 Majority Element
查看>>
关于加密的一些笔记
查看>>
我的友情链接
查看>>
Oracle 数据库查看client的用户登录信息包括ip
查看>>
Kernel Trace System
查看>>
linux文件系统详解
查看>>
我的友情链接
查看>>
ibatis mybatis sql语句配置 符号不兼容 大于号 小于号
查看>>