天天看点

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序
教程中的项目请跟着在pycharm中写一遍,注意查看注释内容。推荐的课外练习请自行完成,完成后再查看参考代码。

本章知识点:

  • python基础
  • 使用requests库发送请求
  • 使用beautifulsoup解析网页源码

python基础学习

本教程爬虫开发需要python语言基础,请根据自身情况选择:

  • 我是零基础:请先学习python基础教程,强烈推荐:廖雪峰的python教程。
    • 重点学习章节:python基础、函数、高级特性、模块、面相对象编程、错误、调试和测试、IO编程。
    • 初步了解章节:进程和线程、正则表达式、常用内建模块、常用第三方模块、virtualenv、网络编程、Web开发。这些内容 十分重要 ,但初期涉及不多。
    • 暂时跳过章节:面向对象高级编程、函数式编程、图形界面、电子邮件、访问数据库、异步IO、实战,这些内容会在 Python爬虫-高级进阶 系列教程涉及。
    • 学习时间: 2~3天
  • 我有编程基础:直接开始爬虫教程。

第一个爬虫程序:游戏葡萄

创建一个game_grape.py文件,写入代码:

from urllib import request  # 导入urllib中的request模块

response= request.urlopen('http://youxiputao.com/')  # 用urlopen()函数执行一次请求,地址是游戏葡萄的首页,并把返回对象赋值给response变量。
html = response.read().decode()  # 从response中读取结果,解码成str类型的字符串,就是我们的html源码。
print(html)  # 在控制台打印html源码。
           

执行程序,控制台打印出首页的html源码:

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

程序运行成功,超级简单有木有!

其实爬虫的本质就是: 发起请求 获得响应 解析结果 。企业中千万级爬虫、分布式爬虫都是在这个基础上抓取得更快、存储得更多、突破各种反爬虫措施而已。

使用requests进行抓取

使用python内置的urllib包虽然可以进行抓取,但使用非常不方便,特别是面对复杂的网络请求时,使用起来会力不从心。我们来尝试用第三方网络请求工具

requests

重写爬虫。

import requests

response = requests.get('http://youxiputao.com/')
print(response.text)
           

执行程序,报错:

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

requests是第三方库,需要安装后使用:按住

Win+R

,输入powershell(Win10以下输入cmd),按回车键,输入命令

pip install requests

,如图:

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

第一次安装需要下载,如果速度太慢安装失败,可以把下载源更换为清华大学镜像:输入

pip -V

命令,查看pip版本:

  • 高于10.0版本,执行命令:

    pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

  • 低于10.0版本,参考教程:设置pip安装源为国内清华大学镜像

换源之后重新安装

requests

,出现

Successfully installed xxx

即为安装成功。

再次执行代码,成功打印出html源码:

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

源码解析

我们想解析网页源码,获得新闻标题和链接,使用第三方库

BeautifulSoup

解析工具:

pip install bs4

。打开Chrome浏览器,右键点击新闻标题,点击

检查

,查看新闻标题的位置:

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

根据源码位置找到标题,如图:

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

修改代码:

import requests
from bs4 import BeautifulSoup

response = requests.get('http://youxiputao.com/')  # 发起网络请求,获得响应
soup = BeautifulSoup(response.text, 'html.parser')  # 使用BeautifulSoup解析,查找我们想要的内容。html.parser是系统内置的解析方案,可以不填但是会报警告(warning)
ul_node = soup.find('ul', {'class': 'news-list'})  # 查找class值为news-list的ul标签,
li_node = ul_node.find('li')  # 在ul标签下查找第一个li标签
h4_node = li_node.find('h4')  # 在li标签下查找h4标签
a_node = h4_node.find('a')  # 查找a标签
print(a_node.text)  # 打印出a标签内容
print(a_node['href'])  # 打印出a标签链接(href属性的值)
           

成功解析出第一条新闻标题和链接:

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

咦,情况不对,这个链接怎么看起来很别扭?而且只拿到第一条新闻,剩下的怎么办呢?继续修改代码:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin  #从urllib库导入urljoin()函数,用于url拼接

response = requests.get('http://youxiputao.com/')
soup = BeautifulSoup(response.text, 'html.parser')
for li_node in soup.find('ul', {'class': 'news-list'}).find_all('li'):  # 使用find_all()找出所有li标签,在for循环中解析每个<a>标签
    a_node = li_node.find('h4').find('a')  # find()函数返回标签,可以连续查找;find_all()返回的是符合条件的所有标签的数组,需要循环遍历
    title = a_node.text
    href = a_node['href']
    url = urljoin(response.url, href)  # response.url是响应的地址,不一定是原始请求地址哦,因为网站可能会把对请求做重定向
    print(url, title)
           

第一页采集成功:

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

拿到了详情页面的链接,我们继续发送请求,采集详细数据。随便点开一个新闻页面,在chrome中按

F12

键查看页面结构:我们需要标题、时间、正文三部分,并把它们放在一个字典里来表示这条数据。

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

在刚才代码后面继续添加:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin  # 从urllib库导入urljoin()函数,用于url拼接

response = requests.get('http://youxiputao.com/')
soup = BeautifulSoup(response.text, 'html.parser')
for li_node in soup.find('ul', {'class': 'news-list'}).find_all('li'):  # 使用find_all()找出所有li标签,在for循环中解析每个<a>标签
    a_node = li_node.find('h4').find('a')  # find()函数返回标签,可以连续查找;find_all()返回的是符合条件的所有标签的数组,需要循环遍历
    href = a_node['href']
    url = urljoin(response.url, href)  # response.url是响应的地址,不一定是原始请求地址哦,因为网站可能会把对请求做重定向

    response_detail = requests.get(url)  # 用response_detail 来区别之前的response
    soup_detail = BeautifulSoup(response_detail.text, 'html.parser')  # 继续解析
    title = soup_detail.find('h2', class_='title').text  # 可以用class_参数定位标签,仅限包含class、id等字段的标签,字典写法更通用
    publish_time = soup_detail.find('div', {'class': 'pull-left'}).text  # 直接获取div标签的“text”属性,包含div标签下所有子标签的文本
    article = soup_detail.find('div', {'class': 'info-box col-sm-12'}).text
    data = {'title': title, 'publish_time': publish_time, 'article': article}
    print(data)
           

执行程序,采集结果如下:

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

查看结果,发现有两个问题:

  1. 混进了奇怪的“n”字符:n是换行字符,对于字符串首位的空白字符(n,t,空格),可以使用

    strip()

    函数剔除。
  2. 图片去哪儿了: 真实的爬虫项目通常不会采集图片 ,原因很简单:大型网站上千万数据,每条数据几张图片,再多硬盘都装不下。企业中对图片常用的处理方案: 保存图片链接

继续修改刚才的代码:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

response = requests.get('http://youxiputao.com/')
soup = BeautifulSoup(response.text, 'html.parser')
for li_node in soup.find('ul', {'class': 'news-list'}).find_all('li'):
    a_node = li_node.find('h4').find('a')
    href = a_node['href']
    url = urljoin(response.url, href)

    response_detail = requests.get(url)
    soup_detail = BeautifulSoup(response_detail.text, 'html.parser')
    title = soup_detail.find('h2', class_='title').text
    publish_time = soup_detail.find('div', {'class': 'pull-left'}).text.strip()
    article = soup_detail.find('div', {'class': 'info-detail'}).text.strip()  # strip()函数可以过滤字符串首尾的空白字符
    images = []  # 用于存放文章中的图片
    for img_node in soup_detail.find('div', {'class': 'info-detail'}).find_all('img'):  # 找到文章主体节点,继续找到所有<img>图片标签
        img_url = img_node['src']
        images.append(img_url)
    cover = soup_detail.find('div', class_='cover').find('img')['src']  # 封面图片
    images.append(cover)
    data = {'title': title, 'publish_time': publish_time, 'images': images, 'article': article}
    print(data)
           

看看修改后的采集结果:

python find函数_Python爬虫入门到入职02:编写第一个爬虫程序

图片有了,文章开头也没有含换行符了,感觉自己太牛X了!仔细查看字段内容,发现文章中间仍然包含n,

一般来说n字符可以用来标识段落

,不用处理。如果必须处理的话可以使用replace()函数:

article = article.replace('n', '')  # 使用“空字符”来替换“空白字符n”,并重新赋值给article变量
           

最后,我们用面向对象的方式改写程序,完整代码如下:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin


class GameGrapeSpider:  # 声明一个叫“GameGrapeSpider(游戏葡萄爬虫)”的类
    def start(self):  # 爬虫的启动函数
        response = requests.get('http://youxiputao.com/')
        soup = BeautifulSoup(response.text, 'html.parser')
        for li_node in soup.find('ul', {'class': 'news-list'}).find_all('li'):
            a_node = li_node.find('h4').find('a')
            href = a_node['href']
            url = urljoin(response.url, href)

            response_detail = requests.get(url)
            soup_detail = BeautifulSoup(response_detail.text, 'html.parser')
            title = soup_detail.find('h2', class_='title').text
            publish_time = soup_detail.find('div', {'class': 'pull-left'}).text.strip()
            article = soup_detail.find('div', {'class': 'info-detail'}).text.strip()
            images = []  # 用于存放文章中的图片
            for img_node in soup_detail.find('div', {'class': 'info-detail'}).find_all('img'):
                img_url = img_node['src']
                images.append(img_url)
            cover = soup_detail.find('div', class_='cover').find('img')['src']  # 封面图片
            images.append(cover)
            data = {'title': title, 'publish_time': publish_time, 'images': images, 'article': article}
            print(data)


if __name__ == '__main__':  # 程序入口,直接运行game_grape.py才执行,被导入时不会执行
    spider = GameGrapeSpider()  # 创建一个对象
    spider.start()  # 启动爬虫
           
课外练习:抓取以下网站的首页内容
  1. 3DM-新闻频道:标题、时间、来源、作者、编辑、文章、图片字段。
  2. 天天美剧-排行榜:名字、排名、海报(链接)、更新日、状态、分类、最后更新、回归日期、倒计时。
练习答案:

Github地址

下一章 >> Python爬虫入门到入职03:全量抓取

继续阅读