Python web crawler(1)基本用法格式

用with读取文件

# './素材/匹配天气.html'是文件路径,'r'表示读取模式,encoding='UTF-8'指定编码为UTF-8
with open('../素材/匹配天气.html', 'r', encoding='utf-8') as file:
    # 读取文件内容并将其保存在变量data中
    data = file.read()

用with写入文件

with open('../练习答案/股票2.html', mode='w', encoding="gbk") as file:
    file.write(tbodyData[0])

当前内容的类型如果是标签"bs4.element.Tag"的话,写入到文件中 注意 需要类型转换为字符串str()

print(type(soup.find('a', class_="cover").img))
with open('save.txt', 'w') as f:
    f.write(str(soup.find('a', class_="cover").img))
    
#执行结果
<class 'bs4.element.Tag'>
进程已结束,退出代码0

使用bs4中的BeautifulSoup库解析HTML内容 ,'lxml'是指定解析器的一种,它是一个快速而灵活的XML和HTML解析库。

from bs4 import BeautifulSoup
with open('./素材/豆瓣.html', 'r', encoding='UTF-8') as f:
    data = f.read()
soup = BeautifulSoup(data, 'lxml')

创建CSV文件以写入数据

在使用 open 函数创建 CSV 文件时,newline='' 是一个参数,用于指定在写入文件时如何处理行尾符号。在这里,newline='' 的作用是禁止在行尾插入额外的换行符,以防止在Windows系统上出现不必要的空行。

with open('output.csv', 'w', newline='', encoding='gbk') as csvfile:
    csvwriter = csv.writer(csvfile)

获取div标签(只查找第一个div标签

print(soup.div)

.attrs获取标签有哪些属性

print(soup.div.attrs)    # 查看div都有哪些属性值
# {'id': 'db-global-nav', 'class': ['global-nav']}
print(soup.find('div', attrs={"class": "detail-frame"}))
# find第一个,从<div class="detail-frame">到</div>里面的所有内容
print(soup.div.attrs['id'])  # 获取当前div的id属性值
# db-global-nav
print(soup.div.attrs['class'])  # 获取当前div的class属性值
# ['global-nav']

.find查找(find只查找第一个符合的值,不会继续向后查询)

# 查找span标签中,class类为"font-small color-lightgray"的值
print(soup.find('span', class_="font-small color-lightgray"))

# 查找<span>标签中,class类为"fleft gray-link",id值为"icp"的值
print(soup.find('span', class_="gray-link", id="icp"))

这里需要特别注意

  • 因为class是python中类的关键字,因此需要特殊处理为class_(一般在html中只有class这个需要特殊处理,别的到目前还没有出现过)
  • class_="fleft gray-link"这里可以只取"gray-link""fleft"其中任意一个,也可以都取。这里是且的逻辑关系

执行结果1:

<span class="font-small color-lightgray">评分9.7</span>

执行结果2:

<span id="icp" class="fleft gray-link">
    <p>
    © 2005-2017 douban.com, all rights reserved 北京豆网科技有限公司
    </p>
</span>

.find.组合使用

print(soup.find('a', class_="cover"))
print(soup.find('a', class_="cover").img)  # 获取里面的img
print(soup.find('a', class_="cover").img.attrs)  # 获取里面的img  属性
print(soup.find('a', class_="cover").img.attrs['src'])  # 获取里面的img  属性
print(soup.find('a', class_="cover").img['src'])  # 获取里面的img  属性
print(soup.find('a', class_="cover").find('img'))  # 获取里面的img  属性

print(soup.find('a', class_="cover").img)  # 获取里面的img  属性
print(type(soup.find('a', class_="cover").img))  # 查看类型

.find一层一层的拿内容

html的内容架构如下:

<div class="article">
    <h2>虚构类  · · · · · · </h2>
    <ul class="cover-col-4 clearfix">
        <li>
        <a class="cover" href="https://book.douban.com/subject/27104959/"><img src="https://img3.doubanio.com/mpic/s29535271.jpg"/></a>
        <div class="detail-frame">
        <h2>
        <a href="https://book.douban.com/subject/27104959/">离开的,留下的</a>
        </h2>
        </div>
        </li>
    </ul>

通过使用.ul.h2逐一查找数据

print(soup.find("div", class_="article").ul.h2)

使用2次find查找

result = soup.find('ul', class_='cover-col-4 clearfix').find('div', class_='detail-frame').h2.a
print(result)

# 运行结果
<a href="https://book.douban.com/subject/27104959/">离开的,留下的</a>

获取内部的内容,而不是标签.string.text.get_text()

print(soup.find('h2', class_="fleft").text)
print(soup.find('h2', class_="fleft").get_text())    # 等同于text
print(soup.find('h2', class_="fleft").string)    # 如果标签还有嵌套 则为None
print(soup.find('h2', class_="fleft").strings)    # 获取当前下所有文本返回生成器,必须要用列表接收
print(list(soup.find('h2', class_="fleft").strings))  # 返回生成器
print(list(soup.find('h2', class_="fleft").stripped_strings))  # 获取当前下所有文本返回生成器,去除空格

# 多层嵌套
print(soup.find('div', class_="article").h2.a.string)  # 如果标签还有嵌套 则为None
print(soup.find('div', class_="detail-frame").h2.a.text)
print(soup.find('div', class_="detail-frame").h2.a.get_text())  # 等同于text


# 使用CSS选择器语法:find 方法可以接受CSS选择器作为参数,这使得选择更加灵活。例如,你可以直接使用.detail-frame h2 a来选择嵌套结构的元素。
result = soup.find(".detail-frame h2 a").text
print(result)

使用 repr() 查看文本内容原格式

repr() 是一个内置函数,用于返回一个对象的“官方”字符串表示形式。

print(repr(soup.find('div', class_="article").text))

使用 repr() 主要是为了确保字符串的特殊字符得到正确的表示,以便在需要重新创建对象时,能够准确还原原始的字符串。在打印输出或日志中,使用 repr() 可以更清晰地显示字符串的内容。
举例来说,如果soup.find('div', class_="article").text的文本内容是"Hello\nWorld",那么 repr() 就会返回 "'Hello\nWorld'",其中 \n 表示换行符。

select选择器

print(soup.select('h2'))
print(soup.select('ul[class="cover-col-4 clearfix"]'))
print(soup.select('ul[class="cover-col-4 clearfix"] > li'))  # 获取子元素li
print(soup.select('ul[class="cover-col-4 clearfix"] > li > a'))
print(soup.select('ul[class="cover-col-4 clearfix"] > li > a > img'))  # 按照层级
print(soup.select('ul[class="cover-col-4 clearfix"] img'))  # 找到ul里面所有的子孙img标签
img_list = soup.select('ul[class="cover-col-4 clearfix"] img')
for img in img_list:
    # print(img.get('src'))
    print(img['src'])

select选择器能最大化满足你所想获取的数据,请尽量使用此方法获取

result = soup.select('ul.cover-col-4.clearfix div.detail-frame h2 a')
for i in result:
    print(i.text)
    print(i.attrs['href'])
    
'''
离开的,留下的
https://book.shu.com/subject/27104959/
利维坦之书
https://book.shu.com/subject/27149647/
吃瓜时代的儿女们
https://book.shu.com/subject/27176647/
废土
https://book.shu.com/subject/27113794/
巫术师
https://book.shu.com/subject/27071334/
'''
  1. soup.select('ul.cover-col-4.clearfix div.detail-frame h2 a'):

    • 使用 select 方法通过 CSS 选择器语法查找在 soup 对象中(HTML文档的BeautifulSoup表示)所有匹配指定选择器的元素。
    • 选择器字符串 'ul.cover-col-4.clearfix div.detail-frame h2 a' 表示选择所有具有类名 "cover-col-4 clearfix" 的 <ul> 元素中包含有类名 "detail-frame" 的 <div> 元素下的 <h2> 元素内的所有 <a> 元素。
  2. result = ...:

    • 将整个选择器的结果赋值给变量 result。这个结果是一个元素列表,包含所有匹配指定选择器的元素。

所以,这段代码实际上是在HTML文档中查找所有满足指定CSS选择器条件的元素。在这个例子中,它寻找的是位于具有类名 "cover-col-4 clearfix" 的 <ul> 元素中,包含有类名 "detail-frame" 的 <div> 元素下的 <h2> 元素内的所有 <a> 元素。

 

定义一个函数 is_valid_td 用于过滤 <td> 元素,确保不包含 rowsPan 类

# 定义一个函数 is_valid_td 用于过滤 <td> 元素,确保不包含 rowsPan 类
def is_valid_td(tag):
    return tag.name == 'td' and 'rowsPan' not in tag.get('class', [])

# 使用CSS选择器选取所有表格行
rows = soup.select('div.hanml tr')

# 遍历每个表格行
    for row in rows:
        # 查找行中的所有单元格并过滤掉含有 rowsPan 类的 <td> 元素
        cells = row.find_all(is_valid_td)
  1. def is_valid_td(tag)::这一行定义了一个名为 is_valid_td 的函数,该函数以一个 BeautifulSoup 标签对象作为参数(通常被称为 tag)。

  2. tag.name == 'td':这一部分检查 HTML 标签的名称是否为 'td',表示它是一个表格单元格。tag.name 返回标签的名称。

  3. 'rowsPan' not in tag.get('class', []):这一部分检查字符串 'rowsPan' 是否不在标签的类属性列表中。

    • tag.get('class', []):这获取标签的 'class' 属性的值。如果 'class' 属性不存在,则返回一个空列表(由默认值 [] 指定)。

    • 'rowsPan' not in ...:检查 'rowsPan' 是否不在类列表中。

  4. return 语句:如果两个条件都满足,表示标签是一个没有 'rowsPan' 类的有效 <td> 元素,函数返回 True。如果任何条件不满足,函数返回 False

总之,is_valid_td 函数对于没有 'rowsPan' 类的 <td> 标签返回 True,否则返回 False。这个函数在调用 find_all 时被用作筛选条件,选择只有特定条件的 <td> 元素。

 

查看代码
from bs4 import BeautifulSoup
import csv

# 打开HTML文件并用BeautifulSoup解析
with open('../素材/匹配天气.html', 'r', encoding='utf-8') as f:
    soup = BeautifulSoup(f.read(), 'lxml')

# 使用CSS选择器选取所有表格行
rows = soup.select('div.hanml tr')


# 定义一个函数 is_valid_td 用于过滤 <td> 元素,确保不包含 rowsPan 类
def is_valid_td(tag):
    return tag.name == 'td' and 'rowsPan' not in tag.get('class', [])


# 创建一个CSV文件并准备写入数据
with open('output.csv', 'w', newline='', encoding='gbk') as csvfile:
    csvwriter = csv.writer(csvfile)

    # 遍历每个表格行
    for row in rows:
        # 查找行中的所有单元格并过滤掉含有 rowsPan 类的 <td> 元素
        cells = row.find_all(is_valid_td)

        # 构建一个空列表 row_data 用于存储单元格文本内容
        row_data = []

        # 遍历每个单元格
        for cell in cells:
            # 获取单元格的文本内容,并去除首尾空白字符
            cell_text = cell.get_text(strip=True)

            # 将单元格文本内容添加到 row_data 列表中
            row_data.append(cell_text)

        # 将 row_data 列表写入CSV文件的一行
        csvwriter.writerow(row_data)

 

posted @ 2024-01-04 13:50  Magiclala  阅读(30)  评论(0编辑  收藏  举报