抓取ajax技术构成的博客站

目录

  1. 1. 前言
  2. 2. 需要的python库有
  3. 3. headers
  4. 4. 写入数据库
  5. 5. 主要操作
  6. 6. 核心
  7. 7. 代码
  8. 8. 后记
  9. 9. 补充

前言

折腾了一下午,实在是初学,网上找了很多资料,把python的官网提供的库也检索了一边,还好搞定了。

需要的python库有

import urllib.request
import urllib.parse
import re
import MySQLdb
import json

urllib.request这个库不用说,爬取网页信息常用的;urllib.parse这个库,我还是新学的,按照官方的说法叫

该模块定义了一个标准接口,用于分解组件中的统一资源定位符(URL)字符串(寻址方案,网络位置,路径等),将组件组合回URL字符串,并将“相对URL”转换为指定了“基本URL”的绝对URL。

说白了就是补全网址的,通过服务器需回调,post

import re这个库见得不是一天两天了,正则表达式模块
import MySQLdb,python对MySQL操作需要的库,我用的是第三方的库,不是标准库。

headers

爬取得需要,伪装成浏览器。

headers ={
    'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest'
    }
#全局安装headers
opener = urllib.request.build_opener()
opener.addheaders = [headers]
urllib.request.install_opener(opener)

写入数据库

def push_db(a, b, c, d, e): #写入库中
db = MySQLdb.connect(
    host = '127.0.0.1',
    port = 3306,
    user = '*****',     #数据库用户名
    password = '******', #数据库密码
    db = 'blog',
    charset = 'utf8'
)
cur = db.cursor()
sql =  "insert into other_blog (id, build_date, name, url, description) values (%s, %s, %s, %s, %s)"
try:
    cur.execute(sql, (a, b, c, d, e)) 
    cur.close()
    db.commit()
except:
    db.rollback()
    print("再试一次!")
db.close()

主要操作

由于我使用F12=>network=>XHR发现,总共只有五个json包,于是for i in range(0, 5):同时查看了一段源码,便得到了还算满意的正则表达式:

pat_1 = '"id":(.*?),'
pat_2 = '"date":"(.*?)",'
pat_3 = '"name":"(.*?)",'
pat_4 = '"url":"(.*?)"}\S'
pat_5 = '"message":"(.*?)",'

下面是全文件提取,形成一个list

id = re.compile(pat_1, re.S).findall(data)
build_date = re.compile(pat_2, re.S).findall(data)
name = re.compile(pat_3, re.S).findall(data)
url = re.compile(pat_4, re.S).findall(data)
description = re.compile(pat_5, re.S).findall(data)

核心

post的主要操作:可以参考python官方提供的源码及解释

values = {
    'page': str(i+1)
}  
url = 'https://foreverblog.cn/api/blogs'
postdata = urllib.parse.urlencode(data=values).encode('utf8')
data = urllib.request.urlopen(url, data=postdata).read().decode

other

#python官方给的源码
import urllib.request
import urllib.parse
data = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) #这里可以由一个values代替这个字典
data = data.encode('ascii')
with urllib.request.urlopen("http://requestb.in/xrbl82xr", data) as f:
    print(f.read().decode('utf-8'))

代码

import urllib.request
import urllib.parse
import re
import MySQLdb
headers ={
    'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest'
    }
#全局安装headers
opener = urllib.request.build_opener()
opener.addheaders = [headers]
urllib.request.install_opener(opener)

def push_db(a, b, c, d, e): #写入库中
    db = MySQLdb.connect(
        host = '127.0.0.1',
        port = 3306,
        user = '****',     #数据库用户名
        password = '******', #数据库密码
        db = 'blog',
        charset = 'utf8'
    )
    cur = db.cursor()
    sql =  "insert into other_blog (id, build_date, name, url, description) values (%s, %s, %s, %s, %s)"
    try:
        cur.execute(sql, (a, b, c, d, e)) 
        cur.close()
        db.commit()
    except:
        db.rollback()
        print("再试一次!")
    db.close()

for i in range(0, 5):
    values = {'page': str(i+1)}
    url = 'https://foreverblog.cn/api/blogs'
    postdata = urllib.parse.urlencode(values).encode('utf8')
    data = urllib.request.urlopen(url, data=postdata).read().decode('utf8')

    pat_1 = '"id":(.*?),'
    pat_2 = '"date":"(.*?)",'
    pat_3 = '"name":"(.*?)",'
    pat_4 = '"url":"(.*?)"}\S'
    pat_5 = '"message":"(.*?)",'

    id = re.compile(pat_1, re.S).findall(data)
    build_date = re.compile(pat_2, re.S).findall(data)
    name = re.compile(pat_3, re.S).findall(data)
    url = re.compile(pat_4, re.S).findall(data)
    description = re.compile(pat_5, re.S).findall(data)

    for j in range(0, len(id)):
        a = json.loads(json.dumps(id[j].encode('utf-8').decode('unicode_escape')))
        b = json.loads(json.dumps(build_date[j].encode('utf-8').decode('unicode_escape')))
        c = json.loads(json.dumps(name[j].encode('utf-8').decode('unicode_escape')))
        d = json.loads(json.dumps(url[j].encode('utf8').decode("unicode_escape").replace("\/", "/")))
        e = json.loads(json.dumps(description[j].encode('utf-8').decode('unicode_escape')))))
        push_db(int(a), b, c, d, e) #网站编辑器的原因,源码是对齐上一行的开头的
'''
    print(id)
    print(build_date)
    print(name)
    print(url)
    print(description)
    print("\n\n")
'''

后记

这个编码问题也是一个很重要的问题,
request输出的是str数据类型
而该网站post的结果是以json文件的形式传输的,所有需要解码json的库import json,同时也要解码unicode,将其转换成中文。
还有这里parse = urllib.parse.urlencode(values).encode('utf8')犯了一个错误,不应当转换成bytes类型,没必要,多了格式转换步骤。
参考资料:
1.UnicodeEncodeError: ‘utf-8’ codec can’t encode characters in position 10-11: surrogates not allowed
2.json.dumps()和json.loads()

补充

2020-5-14
其实不使用urlopen,改用Request更好,Request的拓展性更好。