吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4001|回复: 39
收起左侧

[Python 转载] 新手--某美女图片爬取

  [复制链接]
Ace803 发表于 2022-4-23 21:45
代码写的很糙,希望各位大佬莫笑,自学了一段时间,还在学习的过程中
昨天学了bs4,就想哪来练练手,于是有了今天的这段代码,希望大佬指正一下,代码不通顺需要提高的地方,并注释一下,将不胜感激!!!
代码如下:


# coding:utf-8 学好python,天天向上

import requests
from bs4 import BeautifulSoup
import time

ms=int(input('请输入爬取内容:1、性感美女 2、清纯可爱 3、性感御姐 4、制服诱惑'))
page=1
url1="https://dimgw.us/xinggan/page/"+str(page) # 性感美女
url2="https://dimgw.us/qc/page/"+str(page)      # 清纯可爱
url3="https://dimgw.us/yj/page/"+str(page)      # 性感御姐
url4="https://dimgw.us/zf/page/"+str(page)      # 制服诱惑

if ms==1:
    url=url1
elif ms==2:
    url=url2
elif ms==3:
    url=url3
elif ms==4:
    url=url4
else:
    print('输入有误,请重新输入')
headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36",
    "Referer":"https://dimgw.us/zf"
        }
domain_resp=requests.get(url,headers=headers)
domain_page=BeautifulSoup(domain_resp.text,'html.parser')
# print(domain_page)
a_tag=domain_page.find_all('h2',class_="entry-title")   # 拿到想要的标签内容
# print(a_tag)
while True:
    for child_href in a_tag:
        b_tag=child_href.find_all('a')
        # print(b_tag)
        c_tag=str(b_tag)[10:36] # 对内容进行切割,获取网址
        # href=c_tag.get('href')
        # print(c_tag)
        child_resp=requests.get(c_tag,headers=headers)
        child_page=BeautifulSoup(child_resp.text,'html.parser')
        # print(child_page)
        # 未完成,子页面内图片跳转到另外网站
        div=child_page.find('div',class_="entry-content u-text-format u-clearfix").find_all('img')  # 获取子页面内img标签内容
        # print(div)
        for it in div:
            src=it.get('src')   # 拿到页面内的图片下载地址
            img_name= src.split('/')[-1]
            # print(src)
            img=requests.get(src,headers=headers)
            img.content
            with open(r'练习小说/'+img_name,'wb') as f: # 报错:OSError: [Errno 22] Invalid argument:
                f.write(img.content)
            print('完成',img_name)
            time.sleep(1)
            f.close()
    page+=1
print('下载完成')

免费评分

参与人数 7吾爱币 +4 热心值 +6 收起 理由
zhaoqingdz + 1 谢谢@Thanks!
zzzzzyihang + 1 热心回复!
kyslex + 1 + 1 用心讨论,共获提升!
tyb002 + 1 我很赞同!
qinni8513 + 1 + 1 谢谢@Thanks!
shou0823 + 1 + 1 学习了一段时间有些晕
XAQ1113 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

MyModHeaven 发表于 2022-4-24 10:23
  • 我也在学爬虫,来讨论一下

1

ms=int(input('请输入爬取内容:1、性感美女 2、清纯可爱 3、性感御姐 4、制服诱惑'))
page=1
url1="https://dimgw.us/xinggan/page/"+str(page) # 性感美女
url2="https://dimgw.us/qc/page/"+str(page)      # 清纯可爱
url3="https://dimgw.us/yj/page/"+str(page)      # 性感御姐
url4="https://dimgw.us/zf/page/"+str(page)      # 制服诱惑

if ms==1:
    url=url1
elif ms==2:
    url=url2
elif ms==3:
    url=url3
elif ms==4:
    url=url4
else:
    print('输入有误,请重新输入')
  • 我感觉这部分不太优雅,这样写应该也一样:
urls = ['xinggan', 'qc', 'yj', 'zf']
try:
    ms=int(input('请输入爬取内容:1、性感美女 2、清纯可爱 3、性感御姐 4、制服诱惑'))
    url = 'https://dimgw.us/' + urls[ms-1]
except ValueError:
    print('请输入一个整数,重新输入:')
except IndexError:
    print('输入有误,请重新输入:')
except:
    print('未知错误')
  • 没看明白 url1="https://dimgw.us/xinggan/page/"+str(page) ,四个 url 字符串为什么要拼接一个 str(page)?而且 page 是个常量

2

  • 我习惯把requests发送请求部分写成一个函数,像这个程序中有 3 次请求,第三次是下载图片,那我喜欢写成这样:
def req(url, dire=True):                                        # dire 就是 direction 的简写,我发明的(自己造的)
    headersvalue = {}
    r = requests.get(url, headers=headersvalue)
    sc = BeautifulSoup(r.text, 'lxml') if True else r.content   # sc 就是 soup 和 content 的简写,我发明的(自己造的)
    return sc

3. for 循环中的一些细节

  • a_tag 中每个元素下只有一个 a 节点,可以用 find() 方法,直接返回 Tag 对象,随取随用,不然 find_all() 方法返回一个列表,还要从列表中取出来,多此一举。不过,像下面那样 str()获得网址的方式,倒是无所谓。这个相信你也知道,不过我见看见了就说出来,显得内容多不是,嘿嘿

  • 获取 c_tag 的方式有些独特,没见过也没想到的方式,竟然把 Tag 对象转成字符串,然后切片。初见有些惊讶,细想却感觉粗糙,一般不是通过属性值得到网址吗?我在网上见过的源码也都是这样做的。就像后面下载图片那部分你写的,用get()方法,不过下面注释里那条语句好像写错了,应该是 href=b_tag.get('href')。这样的话,合起来就是:url = child_href.find('a')['href']

  • bs4 里获取节点属性的方法除了get(),还有 Tag 对象的attrs属性,这两天我又发现了一种更简便的方法,就是上面url = child_href.find('a')['href']中用的:Tag[属性值]。分享一下,不知道你知道不知道

  • 下载图片时的命名问题(个人向):用 img 节点的 title 属性命名不好吗,图片网址中一堆字母和数字的名字没什么作用,传递不了什么有用的信息

  • 用 with 语句打开文件,就不用用 close() 方法关闭文件了,会自动关上,python官方文档上有个地方有写

4

while True部分,最后的page += 1什么作用啊?这个循环体内好像没有和 page 这个变量有关的东西,整个 while True好像是个死循环。我没运行整个代码,但应该就是死循环,因为 VS Code 提示了,程序最后一行的 print 语句 Code is unreachable

总结

我按照自己的习惯,写了一个,讨论一下:(变量名尽量按照你的来,方便对照)

import requests
from bs4 import BeautifulSoup

def req(url, dire=True):
    headersvalue = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36",
    "Referer":"https://dimgw.us/zf"
        }
    r = requests.get(url, headers=headersvalue)
    sc = BeautifulSoup(r.text, 'lxml') if dire else r.content
    return sc

urls = ['xinggan', 'qc', 'yj', 'zf']
try:
    ms=int(input('请输入爬取内容:1、性感美女 2、清纯可爱 3、性感御姐 4、制服诱惑'))
    url = 'https://dimgw.us/' + urls[ms-1]
except ValueError:
    print('请输入一个整数,重新输入:')
except IndexError:
    print('输入有误,请重新输入:')
except:
    print('未知错误')

a_tag = req(url)('h2',class_="entry-title")
for child_href in a_tag:
    c_tag = child_href.find('a')['href']
    div = req(c_tag).find('div',class_="entry-content u-text-format u-clearfix")('img')
    for it in div:
        img_url, img_name = it['src'], it['title']
        with open(f'd:/test/{img_name}.webp','wb') as f:
            f.write(req(img_url, dire=False))
        print(img_name + '下载完成')
print('下载完成')
MyModHeaven 发表于 2022-4-24 19:06
Ace803 发表于 2022-4-24 12:18
第一个问题,是我确实懒得写排除了,就是凑合一下,但是你写的代码比我漂亮多了,也学习了
第二个问题中 ...

这是我学 bs4 写的笔记,一起学习。Tag 对象的 attrs 属性里面有介绍


https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/#
https://beautifulsoup.cn/

  • beautifulsoup4库也称为Beautiful Soup库或bs4库,用于解析 HTML 或 XML 文档

  • beautifulsoup4库是一个第三方库

  • beautifulsoup4库可以自动将输入文档转换为 Unicode 编码,将输出文档转换为 UTF-8 编码,故不需要考虑编码方式

  • beautifulsoup4库在解析网页时需要依赖解析器,支持的解析器:

解析器 使用方法 优点 缺点
python 标准库中的 HTML 解析器 BeautifulSoup(markup,'html.parser') python 的内置标准库,执行速度适中,文档容错能力强 python 2.73 或3.2.2 前的版本文档容错能力差
lxml HTML 解析器 BeautifulSoup(markup,'lxml') 速度快,文档容错能力强 需要安装 C 语言库
lxml XML 解析器 BeautifulSoup(markup,'xml') 速度快,唯一支持 XML 的解析器 需要安装 C 语言库
html5lib BeautifulSoup(markup,'html5lib') 容错性最好,以浏览器的方式解析文档,生成 HTML5 格式的文档 速度慢,不依赖外部扩展

4 个对象

  • beautiful soup 将复杂 HTML 文档转换成一个复杂的树形结构,每个节点都是 python 对象,所有对象可归纳为 4 种:Tag, NavigableString, BeautifulSoup, Comment

Tag 对象

  • 通俗来讲, Tag 就是 HTML 中的一个个标签

  • 可以利用 Tag 对象.标签名 的方式获取标签的内容,查找的是所有内容中第一个符合要求的标签

  • 可以利用 Tag 对象[属性名]的方式获取标签的属性值,返回一个 list

  • Tag 对象有 4 个常用属性:

属性 说明
name 标签的名字,如 head、title 等,返回一个字符串
string 标签所包围的文字,网页中真实的文字,返回一个字符串
attrs 字典,包含了页面标签的所有属性,返回一个字典,可通过attrs['属性名']获取属性值
contents 这个标签下所有子标签的内容(HTML 源码),返回一个列表
  • 按照 HTML 语法,可以在标签中嵌套其他标签,因此string属性的返回值遵遵循如下原则:
    1. 如果标签内部没有其他标签, string 属性返回其中的内容
    2. 如果标签内部还有其他标签,但只有一个标签, string 属性返回最里面标签的内容
    3. 如果标签内部还有其他标签,且不止一个标签, string 属性返回 None

此外,还有一些属性:

属性 说明
children 返回所有的子节点
desecndants 返回所有子孙节点
parent 返回父节点
parents 返回父节点的父节点
next_siblings
previous_siblings
  • .content 属性和 .childern 属性获取直接子节点,前者返回一个 list,后者返回一个 list 生成器对象,可以通过遍历获取所有子节点:
for child in soup.body.children:
    print(child)

.desecndants 属性也返回一个 list 生成器对象

NavigableString 对象

  • Tag 对象的 string 属性返回的内容就是 NavigableString 对象

BeautifulSoup 对象

  • BeautifulSoup 对象表示的是一个文档的全部内容。大部分时候可以当作 Tag 对象,是一个特殊的 Tag

Comment 对象

  • Comment 注释对象是一个特殊类型的 NavigableString 对象,其内容不包括注释符号
>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup('<b><!--This is comment--></b>')
>>> print(type(soup.find('b').string))
<class 'bs4.element.Comment'>
  • 解析网页时:

    1. 需要使用BeautifulSoup()创建一个BeautifulSoup对象

    > 该对象是一个树形结构,包含了 HTML 页面中的标签元素,如 <head>、<body> 等。也就是说,HTML 中的主要结构都变成了BeautifulSoup对象的一个个属性

  1. 然后可通过对象名.属性名的形式获取该对象的第一个属性值(即节点)

    > BeautifulSoup对象的属性名与 HTML 的标签名相同

搜索文档树

find_all

find_all(name, attrs, recursive, string, limit)

find_all() 方法搜索当前 tag 的所有 tag 子节点,并判断是否符合过滤器的条件

  1. name:通过 HTML 标签名直接查找节点。如果 name 参数是正则表达式,则通过正则表达式的 match() 来匹配内容
  2. attrs:通过 HTML 标签的属性查找结点(需列出属性名和值),可以同时设置多个属性
  3. recursive:搜索层次,默认查找当前标签的所有子孙节点,如果只查找标签的子节点,可以使用参数 recursive=False
  4. string:通过关键字检索 string 属性内容,传入的形式可以是字符串,也可以是正则表达式对象
  5. limit:返回结果的个数,默认返回全部结果

find_all()方法通过属性查找结点时,对于一些常用的属性(如 id 和 class 等),可以不用 attrs 字典形式来传递,而用复制的形式直接传入参数(如find_all(class_='hotnews'),由于 class 在 python 中是一个关键字,所以后面需要加一个下划线

  • 由于 find_all() 方法非常常用,所以在 bs4 中,BeautifulSoup 对象和 tag 对象可以被当作一个 find_all() 方法使用,即 bs.find_all('a') 和 bs('a') 是等效的,soup.title.find_all(text='abc') 和 soup.title(text='abc') 是等效的
import requests
from bs4 import BeautifulSoup
import re
url = ''
r = requests.get(url)
soup = BeautifulSoup(r.text, 'lxml')
print('所有 span 节点个数:', len(soup.find_all('span')))
print('class 属性值为 “amount” 的所有 span 节点:')
for node in soup.find_all('span', attrs={'class': 'amount'}):
    print(node)
print('前 3 个 class 属性值为 “amount” 的 span 节点:\n', soup.find_all('span', attrs={'class': 'amount'}, limits=3))
print('string 属性值包含 “2室1厅” 的前三个节点的文本:', soup.find_all(string=re.compile('2室1厅'), limit=3))

find

  • find()方法的用法与find_all()方法相似,但其返回结果是第一个匹配的节点

其他查询方法

  • find_parents()find_parent():前者返回所有祖先节点,后者返回直接父节点
  • find_next_siblings()find_next_sibling():前者返回后面所有的兄弟节点,后者返回后面的第一个兄弟节点
  • find_previous_siblings()find_previous_sibling():前者返回前面所有的兄弟节点,后者返回前面的第一个兄弟节点
  • find_all_previous()find_previous():前者返回节点前所有符合条件的节点,后者返回节点前第一个符合条件的节点

多值属性

  • HTML 中定义了一系列可以包含多个值的属性,最常见的多值属性是 class ,还有 rel, rev, accept-charset, headers, accesskey

  • 在 Beautiful Soup 中多值属性的返回类型是 list

    soup = BeautifulSoup('<p class="body strikeout"></p>')
    soup.p['class']
    # ["body", "strikeout"]
    
    soup = BeautifulSoup('<p class="body"></p>')
    soup.p['class']
    # ["body"]
  • 如果某个属性值看起来好像有多个值,但在任何版本的 HTML 定义中都没有被定义为多值属性,那么 Beautiful Soup 会将这个属性组为字符串返回

    id_soup = BeautifulSoup('<p id="my id"></p>')
    id_soup.p['id']
    # 'my id'
  • find_all()find()方法中,根据属性筛选节点时,若某个节点的多值属性的一个属性值与给出的属性值相同,也会出现在结果中

CSS 选择器

  • beautifulsoup4库还提供了使用 CSS 选择器来选择节点的方法(调用select()方法传入相应的 CSS 选择器,返回一个 list,用 get_text() 方法或 text 属性获取文本)

  • CSS 常用的选择器:

选择器 示例 示例说明
.class .intro 选择class="intro"的所有节点
#id #firstname 选择`id="firstname"的所有节点
* * 选择所有节点
element p 选择所有<p>节点
element,element div,p 选择所有<dic>节点和所有<p>节点
element element div p 选择<div>节点内部的所有<p>节点
element>element div>p 选择父节点为<div>节点的所有<p>节点
[attribute] [target] 选择带有 target 属性的所有节点
[attribute=valur] [target=blank] 选择 target="blank" 的所有节点
:link a:link 选择所有未访问的链接
:visited a:visited 选择所有已访问的链接
:active a:active 选择活动链接
:first-line p:first-line 选择每个<p>节点的首行
element1~element2 p~ul 选择前面有<p>节点的所有<ul>节点
[attribute^=value] a[src^="https"] 选择其 src 属性值以 “https” 开头的所有<a>节点
[attribute$=value] a[src$=".pdf"] 选择其 src 属性值以 “.pdf” 结尾的所有<a>节点
[attribute*=valur] a[src*="abc"] 选择其 src 属性值中包含 “abc” 字串的所有<a>节点
:enabled input:enabled 选择每个启用的<input>节点
:disabled input:disabled 选择每个禁用的<input>节点
:checked input:checked 选择每个被选中的<input>节点
import requests
from bs4 import BeautifulSoup
url = ''
r = requests.get(url)
soup = BeautifulSoup(r.text, 'lxml')
print('div 节点下所有 a 结点的个数:', len(soup.select('div a')))
# 获取第一个 calss 属性值为 “list-main-header” 的节点下所有 a 节点
node_a = soup.select('.list-main-header')[0].select('a')
print('第一个 a 节点的 href 属性值:', node_a[0]['href'])
print('第一个 a 节点的文本:', node_a[0].string)

实例

  • 在 当当网 搜索 python,爬取该网页中图书的书名、作者、出版社和价格,保存到本地
import requests
from bs4 import BeautifulSoup

def req(url):
    headersvalue = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 Edg/99.0.1150.52'}
    r = requests.get(url, headers=headersvalue)
    soup = BeautifulSoup(r.text, 'lxml')
    return soup

url = 'http://search.dangdang.com/?key=python&act=input'
node_li = req(url).find('ul', {'class': 'bigimg'}).select('li')
book_detail = []
for li in node_li:
    name = li.a.attrs['title']
    author = li.find('p', class_='search_book_author').span.a.attrs['title']
    publisher = li.find('a', dd_name = '单品出版社').string
    price = li.find('span', class_='search_now_price').string
    book_detail.append('{}, {}, {}, {}'.format(name, author, publisher, price))

with open('d:/book_detail.txt', 'w', encoding='utf-8') as f:
    f.write('\n'.join(book_detail))
yuqilin234 发表于 2022-4-23 21:53
414246704 发表于 2022-4-23 21:57
请问朋友是在哪里自学的,我也想学爬虫,你有好的教程推荐吗?
 楼主| Ace803 发表于 2022-4-23 21:58

从早上9点,到晚上9点多,写了两个爬虫,这是其中之一,另外一个是小说的爬虫,一天都在解决bug和报错了
 楼主| Ace803 发表于 2022-4-23 22:02
414246704 发表于 2022-4-23 21:57
请问朋友是在哪里自学的,我也想学爬虫,你有好的教程推荐吗?

先在b站看的基础的,是杨淑娟老师讲的,挺好懂得,只是自己练习还是挺难的
然后又看的爬虫教学,看的头都大了
现在自己试着写些爬虫,头要爆炸了
winjie1975 发表于 2022-4-23 22:06
谢谢,辛苦了。顶一个。
wuaiwuai888 发表于 2022-4-23 22:16
这个网站良心啊,不用登陆都能直接下载压缩包
 楼主| Ace803 发表于 2022-4-23 22:17
wuaiwuai888 发表于 2022-4-23 22:16
这个网站良心啊,不用登陆都能直接下载压缩包

是的,主要是练手
8970665 发表于 2022-4-23 22:20
哦这东西蛮有趣的
adf28 发表于 2022-4-23 22:27
这个挺好的
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 04:23

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表