python网络爬虫(web spider)系统化整理总结(二):爬虫python代码示例(两种响应格式:json和html)

        上一篇博客(入门知识篇),对爬虫有了一个基本的了解,但是具体怎么实现一个爬虫程序呢?

        一般情况下,我们在浏览器获取信息,是向服务器发送一个http请求,要么返回html页面,要么是ajax请求返回一串json数据,以更新当前网页中局部信息。这里用两个例子分别学习下爬虫的基本操作。

         以下代码是基于python3.6环境。


一、百度在线翻译的自动联想功能

百度在线翻译有这样一个功能,如下图,输入一个字母w,下面黄框里实时就会联想出来几个w开头的单词并有相应的翻译,分析可见,是网页自动发送了一个post请求"https://fanyi.baidu.com/sug",并且只有一个参数。那么我们怎么利用这个API实现我们自己的联想功能呢?

参数列表:

 

再看下其返回结果:

我们模拟浏览器发送这个请求,将获得这样的json字符串,解析之后,就可以拿到联想到的单词和相应的翻译了:

# 使用requests
import requests
import json

def fanyi(keyword):

    url = 'https://fanyi.baidu.com/sug'

    # 定义请求参数
    data = {
        'kw' : keyword
    }
    # 通过设置header头,伪装浏览器用户
    headers = {"User-Agent": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)"}
    # 发送post请求,抓取信息
    res = requests.post(url,data=data,headers=headers)

    # 解析结果并输出
    # 获取响应的json字串
    str_json = res.text
    # 把json转字典
    myjson = json.loads(str_json)
    # 先判断data里面是否有内容
    if len(myjson['data'])==0:
        print("结果:没有这个词")
        print()
    else:
        # 遍历结果,输出单词和相应的翻译
        for v in myjson['data']:
            print("--联想到的单词:"+v['k'])
            print("--翻译:"+v['v'])
            print()

if __name__ == '__main__':
    while True:
        keyword = input('输入翻译的单词:')
        if keyword == 'q':
            print("-- 结束 --")
            break
        fanyi(keyword)

输出结果如下:

二、使用requests分页爬取猫眼电影中榜单栏目中TOP100榜的所有电影信息,并将信息写入txt文件和数据库中(源码有详细的注释)

和上一个例子不同的是,这次返回的结果是html代码,我们需要通过正则表达式匹配解析出需要的内容;

这里有两点值得注意的:

1、使用requests方式请求得到的html源码,有可能和直接在浏览器选取其中一个元素看到的代码不一致也有可能和右键查看页面源代码不一致,对解析会造成一定的干扰。 这是因为浏览器可能是通过Ajax局部更新的数据,解析之前要注意区分。

2、python中yield的使用(对python使用不是很熟悉的情况下,这个应用还是很新鲜、很特别的):

     关于python中yield的使用说明

     一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。

      yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。

以下是第二个例子的源码:

# URL地址:http://maoyan.com/board/4 其中参数offset表示分页的每页起始条数-1
# 获取信息:{排名,图片,标题,主演,放映时间,评分}

from requests.exceptions import RequestException
import requests
import re,time,json
import pymysql

def getPage(url):
    '''爬取指定url页面信息'''
    try:
        #定义请求头信息(模拟浏览器)
        headers = {
            'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'
        }
        # 执行爬取
        res = requests.get(url,headers=headers)
        #判断响应状态,并响应爬取内容
        if res.status_code == 200:
            return res.text
        else:
            return None
    except RequestException:
        return None

def parsePage(html):
    '''解析爬取网页中的内容,并返回字段结果
       这里有个问题,使用requests获取的网页html和在浏览器中从页面中选择一个元素对应的html代码可能不一致
    '''
    #定义解析正则表达式(关于正则表达式的写法用法,后面有机会再探讨)
    pat = '<i class="board-index board-index-[0-9]+">([0-9]+)</i>.*?' \
          '<img data-src="(.*?)" alt="(.*?)" class="board-img" />.*?' \
          '<p class="star">(.*?)</p>.*?' \
          '<p class="releasetime">(.*?)</p>.*?' \
          '<i class="integer">([0-9\.]+)</i>' \
          '<i class="fraction">([0-9]+)</i>'
    # print(html)
    #执行解析
    items = re.findall(pat,html,re.S)
    #遍历封装数据并返回
    for item in items:
        print("item : ",item)
        yield {
            'index':item[0],
            'image':item[1],
            'title':item[2],
            'actor':item[3].strip()[3:],
            'time':item[4].strip()[5:],
            'score':item[5]+item[6],
        }

def writeDB(content):
    """
    写入数据库
    :param content:
    :return:
    """
    print(content)
    print(content["index"])

    db = pymysql.connect("127.0.0.1", "root", "root", "myspider_001")
    cursor = db.cursor()
    sql = "insert into tb_results (index0,image,title,actor,time,score) \
           values ('%s','%s','%s','%s','%s','%s')"% \
          (content['index'],content['image'],content['title'],content['actor'],content['time'],content['score'])
    print(sql)
    try:
        cursor.execute(sql)
        print("qq")
        db.commit()
    except:
        print("q")
        db.rollback()


def writeFile(content):
    '''执行文件追加写操作'''
    #print(content)
    with open("./result.txt",'a',encoding='utf-8') as f:
        f.write(json.dumps(content,ensure_ascii=False) + "\n")
        #json.dumps 序列化时对中文默认使用的ascii编码.想输出真正的中文需要指定ensure_ascii=False

def main(offset):
    ''' 主程序函数,负责调度执行爬虫处理 '''
    url = 'http://maoyan.com/board/4?offset=' + str(offset)
    #print(url)
    html = getPage(url)
    #判断是否爬取到数据,并调用解析函数
    if html:
        for item in parsePage(html):
            writeFile(item)
            writeDB(item)


# 判断当前执行是否为主程序运行,并遍历调用主函数爬取数据
if __name__ == '__main__':
    # 前100名,每页10名,分页参数offset 0 10 20 ...90
    for i in range(10):
        main(offset=i*10)
        time.sleep(1)

学完这两个基本的例子,就对爬虫有了一个初步的认识。

后面还会继续学习,写下来,一方面是个总结和记录,一方面希望有可能帮到和我一样的初学者。

猜你喜欢

转载自blog.csdn.net/ejiao1233/article/details/82929310