爬取Ajax动态加载网页

常见的反爬机制及处理方式

1、Headers反爬虫 :Cookie、Referer、User-Agent

解决方案: 通过F12获取headers,传给requests.get()方法

2、IP限制 :网站根据IP地址访问频率进行反爬,短时间内进制IP访问

解决方案:

1、构造自己IP代理池,每次访问随机选择代理,经常更新代理池

2、购买开放代理或私密代理IP

3、降低爬取的速度

3、User-Agent限制 :类似于IP限制

解决方案: 构造自己的User-Agent池,每次访问随机选择

5、对查询参数或Form表单数据认证(salt、sign)

解决方案: 找到JS文件,分析JS处理方法,用Python按同样方式处理

6、对响应内容做处理

解决方案: 打印并查看响应内容,用xpath或正则做处理

python中正则处理headers和formdata

1、pycharm进入方法 :Ctrl + r ,选中 Regex

2、处理headers和formdata

(.*): (.*)

"$1": "$2",

3、点击 Replace All

民政部网站数据抓取

目标: 抓取最新中华人民共和国县以上行政区划代码

URL: http://www.mca.gov.cn/article/sj/xzqh/2019/ - 民政数据 - 行政区划代码

实现步骤

1、从民政数据网站中提取最新行政区划代码链接

  最新的在上面,命名格式: 2019年X月中华人民共和国县以上行政区划代码

import requests
from lxml import etree
import re
?
url = ‘http://www.mca.gov.cn/article/sj/xzqh/2019/‘
headers = {‘User-Agent‘:‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36‘}
html = requests.get(url, headers=headers).text
parse_html = etree.HTML(html)
article_list = parse_html.xpath(‘//a[@class="artitlelist"]‘)
?
for article in article_list:
    title = article.xpath(‘./@title‘)[0]
    # 正则匹配title中包含这个字符串的链接
    if title.endswith(‘代码‘):
        # 获取到第1个就停止即可,第1个永远是最新的链接
        two_link = ‘http://www.mca.gov.cn‘ + article.xpath(‘./@href‘)[0]
        print(two_link)
        break

2、从二级页面链接中提取真实链接(反爬-响应网页内容中嵌入JS,指向新的网页链接)

  1. 向二级页面链接发请求得到响应内容,并查看嵌入的JS代码
  2. 正则提取真实的二级页面链接
# 爬取二级“假”链接two_html = requests.get(two_link, headers=headers).text
# 从二级页面的响应中提取真实的链接(此处为JS动态加载跳转的地址)
new_two_link = re.findall(r‘window.location.href="(.*?)"‘, two_html, re.S)[0]

3、在数据库表中查询此条链接是否已经爬取,建立增量爬虫

  1. 数据库中建立version表,存储爬取的链接
  2. 每次执行程序和version表中记录核对,查看是否已经爬取过
cursor.execute(‘select * from version‘)
result = self.cursor.fetchall()
if result:
   if result[-1][0] == two_link:
       print(‘已是最新‘)
   else:
       # 有更新,开始抓取
       # 将链接再重新插入version表记录

4、代码实现

import requests
from lxml import etree
import re
import pymysql

class GovementSpider(object):
    def __init__(self):
        self.url = ‘http://www.mca.gov.cn/article/sj/xzqh/2019/‘
        self.headers = {‘User-Agent‘: ‘Mozilla/5.0‘}
        # 创建2个对象
        self.db = pymysql.connect(‘127.0.0.1‘, ‘root‘, ‘123456‘, ‘govdb‘, charset=‘utf8‘)
        self.cursor = self.db.cursor()

    # 获取假链接
    def get_false_link(self):
        html = requests.get(url=self.url, headers=self.headers).text
        # 此处隐藏了真实的二级页面的url链接,真实的在假的响应网页中,通过js脚本生成,
        # 假的链接在网页中可以访问,但是爬取到的内容却不是我们想要的
        parse_html = etree.HTML(html)
        a_list = parse_html.xpath(‘//a[@class="artitlelist"]‘)
        for a in a_list:
            # get()方法:获取某个属性的值
            title = a.get(‘title‘)
            if title.endswith(‘代码‘):
                # 获取到第1个就停止即可,第1个永远是最新的链接
                false_link = ‘http://www.mca.gov.cn‘ + a.get(‘href‘)
                print("二级“假”链接的网址为", false_link)
                break
        # 提取真链接
        self.incr_spider(false_link)

    # 增量爬取函数
    def incr_spider(self, false_link):
        self.cursor.execute(‘select url from version where url=%s‘, [false_link])
        # fetchall: ((‘http://xxxx.html‘,),)
        result = self.cursor.fetchall()

        # not result:代表数据库version表中无数据
        if not result:
            self.get_true_link(false_link)
            # 可选操作: 数据库version表中只保留最新1条数据
            self.cursor.execute("delete from version")

            # 把爬取后的url插入到version表中
            self.cursor.execute(‘insert into version values(%s)‘, [false_link])
            self.db.commit()
        else:
            print(‘数据已是最新,无须爬取‘)

    # 获取真链接
    def get_true_link(self, false_link):
        # 先获取假链接的响应,然后根据响应获取真链接
        html = requests.get(url=false_link, headers=self.headers).text
        # 从二级页面的响应中提取真实的链接(此处为JS动态加载跳转的地址)
        re_bds = r‘window.location.href="(.*?)"‘
        pattern = re.compile(re_bds, re.S)
        true_link = pattern.findall(html)[0]

        self.save_data(true_link)  # 提取真链接的数据

    # 用xpath直接提取数据
    def save_data(self, true_link):
        html = requests.get(url=true_link, headers=self.headers).text

        # 基准xpath,提取每个信息的节点列表对象
        parse_html = etree.HTML(html)
        tr_list = parse_html.xpath(‘//tr[@height="19"]‘)
        for tr in tr_list:
            code = tr.xpath(‘./td[2]/text()‘)[0].strip()  # 行政区划代码
            name = tr.xpath(‘./td[3]/text()‘)[0].strip()  # 单位名称

            print(name, code)

    # 主函数
    def main(self):
        self.get_false_link()

if __name__ == ‘__main__‘:
    spider = GovementSpider()
    spider.main()

动态加载数据抓取-Ajax

特点

  1. 右键 -> 查看网页源码中没有具体数据
  2. 滚动鼠标滑轮或其他动作时加载

抓取

  1. F12打开控制台,选择XHR异步加载数据包,找到页面动作抓取网络数据包
  2. 通过XHR-->Header-->General-->Request URL,获取json文件URL地址
  3. 通过XHR-->Header-->Query String Parameters(查询参数)

豆瓣电影数据抓取案例

目标

  1. 地址: 豆瓣电影 - 排行榜 - 剧情

  2. 目标: 爬取电影名称、电影评分

F12抓包(XHR)

1、Request URL(基准URL地址) :https://movie.douban.com/j/chart/top_list?

2、Query String Paramaters(查询参数)

# 查询参数如下:
type: 13 # 电影类型
interval_id: 100:90
action: ‘[{},{},{}]‘
start: 0  # 每次加载电影的起始索引值
limit: 20 # 每次加载的电影数量

json文件在以下地址:

基准URL地址+查询参数

https://movie.douban.com/j/chart/top_list?‘+‘type=11&interval_id=100%3A90&action=&start=20&limit=20

代码实现

import requests
import time
from fake_useragent import UserAgent

class DoubanSpider(object):
    def __init__(self):
        self.base_url = ‘https://movie.douban.com/j/chart/top_list?‘
        self.i = 0

    def get_html(self, params):
        headers = {‘User-Agent‘: UserAgent().random}
        res = requests.get(url=self.base_url, params=params, headers=headers)
        res.encoding = ‘utf-8‘
        html = res.json()  # 将json格式的字符串转为python数据类型
        self.parse_html(html)  # 直接调用解析函数

    def parse_html(self, html):
        # html: [{电影1信息},{电影2信息},{}]
        item = {}
        for one in html:
            item[‘name‘] = one[‘title‘]  # 电影名
            item[‘score‘] = one[‘score‘]  # 评分
            item[‘time‘] = one[‘release_date‘]  # 打印测试
            # 打印显示
            print(item)
            self.i += 1

    # 获取电影总数
    def get_total(self, typ):
        # 异步动态加载的数据 都可以在XHR数据抓包
        url = ‘https://movie.douban.com/j/chart/top_list_count?type={}&interval_id=100%3A90‘.format(typ)
        ua = UserAgent()
        html = requests.get(url=url, headers={‘User-Agent‘: ua.random}).json()
        total = html[‘total‘]

        return total

    def main(self):
        typ = input(‘请输入电影类型(剧情|喜剧|动作):‘)
        typ_dict = {‘剧情‘: ‘11‘, ‘喜剧‘: ‘24‘, ‘动作‘: ‘5‘}
        typ = typ_dict[typ]
        total = self.get_total(typ)  # 获取该类型电影总数量

        for page in range(0, int(total), 20):
            params = {
                ‘type‘: typ,
                ‘interval_id‘: ‘100:90‘,
                ‘action‘: ‘‘,
                ‘start‘: str(page),
                ‘limit‘: ‘20‘}
            self.get_html(params)
            time.sleep(1)
        print(‘爬取的电影的数量:‘, self.i)

if __name__ == ‘__main__‘:
    spider = DoubanSpider()
    spider.main()

腾讯招聘数据抓取(Ajax)

确定URL地址及目标

要求与分析

  1. 通过查看网页源码,得知所需数据均为 Ajax 动态加载
  2. 通过F12抓取网络数据包,进行分析
  3. 一级页面抓取数据: 职位名称
  4. 二级页面抓取数据: 工作职责、岗位要求

一级页面json地址(pageIndex在变,timestamp未检查)

https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1563912271089&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=&pageIndex={}&pageSize=10&language=zh-cn&area=cn

二级页面地址(postId在变,在一级页面中可拿到)

https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=1563912374645&postId={}&language=zh-cn

useragents.py文件

ua_list = [
  ‘Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1‘,
  ‘Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0‘,
  ‘Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3)‘,
]
import time
import json
import random
import requests
from useragents import ua_list

class TencentSpider(object):
    def __init__(self):
        self.one_url = ‘https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1563912271089&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=&pageIndex={}&pageSize=10&language=zh-cn&area=cn‘
        self.two_url = ‘https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=1563912374645&postId={}&language=zh-cn‘
        self.f = open(‘tencent.json‘, ‘a‘)  # 打开文件
        self.item_list = []  # 存放抓取的item字典数据

    # 获取响应内容函数
    def get_page(self, url):
        headers = {‘User-Agent‘: random.choice(ua_list)}
        html = requests.get(url=url, headers=headers).text
        html = json.loads(html)  # json格式字符串转为Python数据类型

        return html

    # 主线函数: 获取所有数据
    def parse_page(self, one_url):
        html = self.get_page(one_url)
        item = {}
        for job in html[‘Data‘][‘Posts‘]:
            item[‘name‘] = job[‘RecruitPostName‘]  # 名称
            post_id = job[‘PostId‘]  # postId,拿postid为了拼接二级页面地址
            # 拼接二级地址,获取职责和要求
            two_url = self.two_url.format(post_id)
            item[‘duty‘], item[‘require‘] = self.parse_two_page(two_url)
            print(item)
            self.item_list.append(item)  # 添加到大列表中

    # 解析二级页面函数
    def parse_two_page(self, two_url):
        html = self.get_page(two_url)
        duty = html[‘Data‘][‘Responsibility‘]  # 工作责任
        duty = duty.replace(‘\r\n‘, ‘‘).replace(‘\n‘, ‘‘)  # 去掉换行
        require = html[‘Data‘][‘Requirement‘]  # 工作要求
        require = require.replace(‘\r\n‘, ‘‘).replace(‘\n‘, ‘‘)  # 去掉换行

        return duty, require

    # 获取总页数
    def get_numbers(self):
        url = self.one_url.format(1)
        html = self.get_page(url)
        numbers = int(html[‘Data‘][‘Count‘]) // 10 + 1  # 每页有10个推荐

        return numbers

    def main(self):
        number = self.get_numbers()
        for page in range(1, 3):
            one_url = self.one_url.format(page)
            self.parse_page(one_url)

        # 保存到本地json文件:json.dump
        json.dump(self.item_list, self.f, ensure_ascii=False)
        self.f.close()

if __name__ == ‘__main__‘:
    start = time.time()
    spider = TencentSpider()
    spider.main()
    end = time.time()
    print(‘执行时间:%.2f‘ % (end - start))

原文地址:https://www.cnblogs.com/LXP-Never/p/11374795.html

时间: 2024-10-24 01:14:50

爬取Ajax动态加载网页的相关文章

Python网络爬虫_爬取Ajax动态加载和翻页时url不变的网页

1 . 什么是 AJAX ? AJAX = 异步 JavaScript 和 XML. AJAX 是一种用于创建快速动态网页的技术. 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新. 传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面. 几个常见的用到ajax的场景. 比如你在逛知乎,你没有刷新过网页,但是你却能看到你关注的用户或者话题有了新动态的消息提示. 还比如,我们在看视频时,可以看到下面

Python爬虫学习——使用selenium和phantomjs爬取js动态加载的网页

1.安装selenium pip install selenium Collecting selenium Downloading selenium-3.4.1-py2.py3-none-any.whl (931kB) 100% |████████████████████████████████| 942kB 573kB/s Installing collected packages: selenium Successfully installed selenium-3.4.1 2.安装phan

第三百三十四节,web爬虫讲解2—Scrapy框架爬虫—Scrapy爬取百度新闻,爬取Ajax动态生成的信息

第三百三十四节,web爬虫讲解2-Scrapy框架爬虫-Scrapy爬取百度新闻,爬取Ajax动态生成的信息 crapy爬取百度新闻,爬取Ajax动态生成的信息,抓取百度新闻首页的新闻标题和rul地址 有多网站,当你浏览器访问时看到的信息,在html源文件里却找不到,由得信息还是滚动条滚动到对应的位置后才显示信息,那么这种一般都是 js 的 Ajax 动态请求生成的信息 我们以百度新闻为列: 1.分析网站 首先我们浏览器打开百度新闻,在网页中间部分找一条新闻信息 然后查看源码,看看在源码里是否有

web爬虫讲解—Scrapy框架爬虫—Scrapy爬取百度新闻,爬取Ajax动态生成的信息

crapy爬取百度新闻,爬取Ajax动态生成的信息,抓取百度新闻首页的新闻rul地址 有多网站,当你浏览器访问时看到的信息,在html源文件里却找不到,由得信息还是滚动条滚动到对应的位置后才显示信息,那么这种一般都是 js 的 Ajax 动态请求生成的信息 我们以百度新闻为列: 1.分析网站 首先我们浏览器打开百度新闻,在网页中间部分找一条新闻信息 然后查看源码,看看在源码里是否有这条新闻,可以看到源文件里没有这条信息,这种情况爬虫是无法爬取到信息的 那么我们就需要抓包分析了,启动抓包软件和抓包

python爬取ajax动态生成的数据 以抓取淘宝评论为例子

在学习python的时候,一定会遇到网站内容是通过ajax动态请求.异步刷新生成的json数据的情况,并且通过python使用之前爬取静态网页内容的方式是不可以实现的,所以这篇文章将要讲述如果在python中爬取ajax动态生成的数据. 至于读取静态网页内容的方式,有兴趣的可以查看博客内容. 这里我们以爬取淘宝评论为例子讲解一下如何去做到的. 这里主要分为了四步: 一 获取淘宝评论时,ajax请求链接(url) 二 获取该ajax请求返回的json数据 三 使用python解析json数据 四

Ajax动态加载数据

前言: 1.这个随笔实现了一个Ajax动态加载的例子. 2.使用.net 的MVC框架实现. 3.这个例子重点在前后台交互,其它略写. 开始: 1.控制器ActionResult代码(用于显示页面) /// <summary> /// 电话查询页面 /// </summary> /// <returns></returns> public ActionResult PhoneSearch(string sql) { phoneList=从数据库查询数据: V

Echarts ajax动态加载json数据

后台php写的,给前台准备好json格式数据 public function actionGetOffline(){ $userid = Yii::$app->user->identity->user_id; $connection = Yii::$app->db; $command = $connection->createCommand("SELECT proc_phase_id from tb_pro where user_id like '%$userid%

Jquery chosen动态设置值 select Ajax动态加载数据 设置chosen和获取他们选中的值

在做一个编辑对话框时,要对里面带有select option的操作.主要是想动态加载option和对option的选中.但是由于项目中使用了jquery里的chosen()方法,怎么也无法实现效果.原码如下: Java代码   <select id="viewOLanguage" data-rel="chosen"> <option value="zh">简体中文(简体中文 Chinese)</option>

zTree 树形控件 ajax动态加载数据

很久没搞过树形控件了 , 再次接触看官网文档有点没懂,于是在网上找了个代码copy上,但数据是写死的,就想这在用ajax异步取出数据替换,下面是js代码 <SCRIPT type="text/javascript" > //定义全局ztree数据 var zNodes; /* 初始化ztree数据 */ function initZtree(){ $.ajax({ type: "GET", url: "<%=request.getCont