python爬虫学习(二):使用python获取网站所有文章标题及对应链接

代码如下:

import requests
from bs4 import BeautifulSoup
import json

def download_all_htmls():
    """
    下载所有列表页面的HTML,用于后续的分析
    """
    htmls = []  #列表
    for idx in range(34):  #一共34页
        url = f"http://www.crazyant.net/page/{idx+1}"  #自动爬取所有页面
        print("craw html:", url)
        r = requests.get(url)  #发送GET请求,返回的是一个包含服务器资源的Response对象
        if r.status_code != 200:  #状态码为200则表示服务器已成功处理了请求
            raise Exception("error")
        htmls.append(r.text)
    return htmls

htmls = download_all_htmls()

def parse_single_html(html):
    """
    解析单个HTML,得到数据
    @return list({"link", "title", [label]})
    """
    soup = BeautifulSoup(html, 'html.parser')  #解析html字符串,html.parser表示解析用的解析器
    articles = soup.find_all("article")  #找到article标签,文章的标题和超链接都在article标签里面,find_all()返回的是一个列表
    datas = []  #存放数据的列表
    for article in articles:
        # 查找超链接
        title_node = (
            article
                .find("h2", class_="entry-title")
                .find("a")
        )
        title = title_node.get_text()  #标题
        link = title_node["href"]  #超链接
        # 查找标签列表
        tag_nodes = (
            article
                .find("span", class_="cat-links")
                .find_all("a")   #find_all()返回一个列表
        )  
        tags = [tag_node.get_text() for tag_node in tag_nodes]
        datas.append(
            {"title": title, "link": link, "tags": tags}   #将字典存入列表
        )
    return datas

all_datas = []
for html in htmls:
    all_datas.extend(parse_single_html(html))  #extend() 函数用于在列表末尾一次性追加另一个序列中的多个值

with open("all_article_links.json", "w",encoding='utf-8') as f:
    for data in all_datas:
        f.write(json.dumps(data, ensure_ascii=False)+"\n")

BeautifulSoup

将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象, 可以传入一段字符串或一个文件句柄。首先,文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码。然后,Beautiful Soup选择最合适的解析器来解析这段文档,如果手动指定解析器那么Beautiful Soup会选择指定的解析器来解析文档。

Python标准库中的HTML解析器:BeautifulSoup(markup, “html.parser”):
lxml HTML 解析器:BeautifulSoup(markup, “lxml”) pycharm中先安装wheel库,再安装lxml库
lxml XML 解析器:BeautifulSoup(markup, [“lxml-xml”])
BeautifulSoup(markup, “xml”)
html5lib解析器:BeautifulSoup(markup, “html5lib”) html5lib的解析方式与浏览器相同,生成HTML5格式的文档

输出解析后的文档:

from bs4 import BeautifulSoup
doc = "<html><h1>Heading</h1><p>Text"
soup = BeautifulSoup(doc,'lxml')
print(str(soup))     #使用 str函数将Beautiful Soup文档(或者它的子集)转换为字符串
print(soup.prettify())      #prettify()函数添加了一些换行和空格以便让文档结构看起来更清晰
print(unicode(soup))    #使用unicode()函数以Unicode字符串形式输出,Python 3不能使用unicode()函数

BeautifulSoup能够将复杂的HTML转换成为一个复杂的树形结构,其中每个节点都是python对象,所有这些对象可以分类4大类,分别为:
Tag
NavigableString
BeautifulSoup
Comment

Tag

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b

tag中最重要的属性: name和attributes
Name:
tag.name:获取tag名字
Attributes:
tag[‘属性名’]:查看特定属性,如tag[‘class’],tag[‘id’],soup.p[‘class’]
tag.attrs:查看所有属性
在Beautiful Soup中多值属性的返回类型是list

查找标签的方法:

  1. BeautifulSoup对象.标签名:查看标签内容,如soup.body.b。通过点取属性的方式只能获得当前位置下的第一个标签
  2. find() 和 find_all()
    find_all()和 find()仅对Tag对象以及 顶层剖析对象有效
    soup.find_all(“title”)
    soup.find_all(“p”, “title”)
    soup.find_all(id=“link2”)
    soup.findAll(align=[“center”, “blah”])
    soup.find_all(“a”, class_=“sister”)
    soup.find(string=re.compile(“sisters”)) 通过 string 参数可以搜索文档中的字符串内容
    soup.find_all(href=re.compile(“elsie”), id=‘link1’) 搜索每个tag的”href”属性
    data_soup.find_all(attrs={“data-foo”: “value”})

tag的其它属性:

  1. tag.contentscontents :将tag的子节点以列表的方式输出
  2. tag.children :输出为生成器,可以对tag的子节点进行循环
  3. tag.descendants:可以对所有tag的子孙节点进行递归循环
  4. tag.string :如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点
  5. tag .strings :如果tag中包含多个字符串,可以使用 .strings 来循环获取
  6. tag …stripped_strings :去除输出的字符串中多余空白内容
  7. tag…parent :获取某个元素的父节点
  8. tag.parents:可以递归得到元素的所有父辈节点
  9. tag.next_sibling :查询下兄弟节点
  10. tag.previous_sibling :查询上兄弟节点
  11. tag…next_element:指向解析过程中下一个被解析的对象(字符串或tag)
  12. tag…previous_element :指向当前被解析的对象的前一个解析对象

NavigableString

Beautiful Soup用 NavigableString 类来包装tag中的字符串,字符串不支持 .contents 或 .string 属性或 find() 方法.
如果一个标签只有一个子节点且是字符串类型,可以这样访问 tag.string,等同于tag.contents[0]的形式。

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
print(soup.b.string)
print(soup.b.contents[0])
print(type(soup.b.string))
print(type(soup.b.contents[0]))

结果:
Extremely bold
Extremely bold
<class ‘bs4.element.NavigableString’>
<class ‘bs4.element.NavigableString’>

tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用 replace_with() 方法:

tag.string.replace_with("No longer bold")

BeautifulSoup

BeautifulSoup 对象表示的是一个文档的全部内容,包含了一个值为 “[document]” 的特殊属性 .name
soup.name

Comment

Comment 对象是一个特殊类型的 NavigableString 对象,它是文档的注释部分。

参考文献:
【1】https://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html#Navigating%20the%20Parse%20Tree
【2】https://beautifulsoup.readthedocs.io/zh_CN/latest/#tag

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值