Python爬虫获取10页的图片、文本数据并传入linux上的mysql数据库中

  • Post author:
  • Post category:linux




一、任务需求

爬取网址之家的网站排行信息,共获取6个指标:

在这里插入图片描述

2张图片和4个文本字符串,观察发现每个网页共30个,一共需要爬取10页,并把图片存入PNG目录下,文本信息存入info.txt文件中,最后上传到linux上的Mysql数据库中.



二、实战代码

import requests
import os,sys
import shutil
from bs4 import BeautifulSoup
import pymysql

conn=pymysql.connect(
    host='192.168.1.111',
    user='root',
    passwd='root',
    db='test',
    port=3306
)
cursor=conn.cursor()

#爬第一个页面
response = requests.get(url="https://top.chinaz.com/hangye/")

def get_resource_path(relative_path): # 利用此函数实现资源路径的定位
    if getattr(sys, "frozen", False):
        base_path = sys._MEIPASS # 获取临时资源
        print(base_path)
    else:
        base_path = os.path.abspath(".") # 获取当前路径
    return os.path.join(base_path, relative_path) # 绝对路径

if response.status_code == 200:    #404和405
    print("连接成功!")
    # 设置返回源码的编码格式
    response.encoding = "UTF-8"
    # print(type(response.text))
    html = BeautifulSoup(response.text,"html5lib")
    ul=html.find("ul",attrs={"class":"listCentent"})#找唯一的父节点再找子节点,或者找出后得到列表取第一个
    li_list = ul.find_all("li")

    i = 0
    
    PNG1=get_resource_path('png1')   #判断是否有PNG目录存在,存在则删除再创建,避免使用的时候报错
    if os.path.exists(PNG1):
        shutil.rmtree(PNG1)
    png1 = os.mkdir(PNG1)
    PNG2=get_resource_path('png2')   #判断是否有PNG目录存在,存在则删除再创建,避免使用的时候报错
    if os.path.exists(PNG2):
        shutil.rmtree(PNG2)
    png2 = os.mkdir(PNG2)
    PNG3=get_resource_path('png3')   #判断是否有PNG目录存在,存在则删除再创建,避免使用的时候报错
    if os.path.exists(PNG3):
        shutil.rmtree(PNG3)
    png3 = os.mkdir(PNG3)

    for li in li_list:
        i += 1
        img_src1 = 'https:'+li.find_all("img")[0]["src"]
        response_child1 = requests.get(img_src1)
        fileWriter = open(get_resource_path(os.path.join("png1", "{}.png".format(i))), "wb")
        fileWriter.write(response_child1.content)
        
        img_src2 = 'https://top.chinaz.com'+li.find_all("img")[1]["src"]
        response_child2 = requests.get(img_src2)
        fileWriter1 = open(get_resource_path(os.path.join("png2", "{}.png".format(i))), "wb")
        fileWriter1.write(response_child2.content)
        
        img_src3 = 'https://top.chinaz.com'+li.find_all("img")[2]["src"]
        response_child3 = requests.get(img_src3)
        fileWriter2 = open(get_resource_path(os.path.join("png3", "{}.png".format(i))), "wb")
        fileWriter2.write(response_child3.content)
        
        name=li.find("a",attrs={"class":"pr10 fz14"}).text
        web=li.find("span",attrs={"class":"col-gray"}).text
        p_list=li.find_all("p",attrs={"class":"RtCData"})
        AleaxaRank=p_list[0].find('a').text
        ReChainNum=p_list[3].find('a').text
        
        text=open('info.txt','a',encoding='utf-8')
        if i==1:
            text.write('网站名'+' '+'网址'+' '+'Aleaxa排名'+' '+'反链数'+'\n')
        else:
            text.write(name+' '+web+' '+AleaxaRank+' '+ReChainNum+'\n')
        text.close()
        
        cursor.execute(
            #"create table webs(name varchar(50),web varchar(50),AleaxaRank varchar(50),ReChainNum varchar(50),img_src1 varchar(200),img_src2 varchar(200))"
            "insert into webs(name,web,AleaxaRank,ReChainNum,img_src1,img_src2)values(%s,%s,%s,%s,%s,%s)",
            (str(name),str(web),str(AleaxaRank),str(ReChainNum),str(img_src1),str(img_src2))
        )
        conn.commit()#提交
     
    #爬剩下的9个页面    
    for j in range(0,9):
        div_a_list=html.find("div",attrs={"class":"ListPageWrap"})
        a_list=div_a_list.find_all('a')
        website='https://top.chinaz.com'+a_list[j+2]["href"]
        response = requests.get(url=website,timeout=(3,7))  #防止[WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。
        if response.status_code == 200:    #404和405
            print("连接成功!")
            # 设置返回源码的编码格式
            response.encoding = "UTF-8"
            # print(type(response.text))
            html = BeautifulSoup(response.text,"html5lib")
            ul=html.find("ul",attrs={"class":"listCentent"})#找唯一的父节点再找子节点,或者找出后得到列表取第一个
            li_list = ul.find_all("li")

            for li in li_list:
                i += 1
                img_src1 = 'https:'+li.find_all("img")[0]["src"]
                response_child1 = requests.get(img_src1)
                fileWriter = open(get_resource_path(os.path.join("png1", "{}.png".format(i))), "wb")
                fileWriter.write(response_child1.content)
        
                img_src2 = 'https://top.chinaz.com'+li.find_all("img")[1]["src"]
                response_child2 = requests.get(img_src2)
                fileWriter1 = open(get_resource_path(os.path.join("png2", "{}.png".format(i))), "wb")
                fileWriter1.write(response_child2.content)
        
                img_src3 = 'https://top.chinaz.com'+li.find_all("img")[2]["src"]
                response_child3 = requests.get(img_src3)
                fileWriter2 = open(get_resource_path(os.path.join("png3", "{}.png".format(i))), "wb")
                fileWriter2.write(response_child3.content)
        
                name=li.find("a",attrs={"class":"pr10 fz14"}).text
                web=li.find("span",attrs={"class":"col-gray"}).text
                p_list=li.find_all("p",attrs={"class":"RtCData"})
                AleaxaRank=p_list[0].find('a').text
                ReChainNum=p_list[3].find('a').text
        
                text=open('info.txt','a',encoding='utf-8')
                if i==31:
                    text.write('网站名'+' '+'网址'+' '+'Aleaxa排名'+' '+'反链数'+'\n')
                else:
                    text.write(name+' '+web+' '+AleaxaRank+' '+ReChainNum+'\n')
                text.close()
        
                cursor.execute(
                    "insert into webs(name,web,AleaxaRank,ReChainNum,img_src1,img_src2)values(%s,%s,%s,%s,%s,%s)",
                    (str(name),str(web),str(AleaxaRank),str(ReChainNum),str(img_src1),str(img_src2))
                )
                conn.commit()#提交
else:
    print("连接失败!")






三、步骤分析

<ul class="listCentent">    ##唯一listCentent,获取后得到列表
<li class="clearfix  LCliTheOne">   #第一个li
<div class="leftImg">
<a name="obj_1" target="_blank" id="obj_1" href="/site_www.baidu.com.html">
<img src="//topimg.chinaz.net/WebSiteimages/baiducom/969e383d-19b6-4081-b933-a38ca415dd8a_2017_s.png" onerror="this.src='//topimg.chinaz.net/WebSiteimages/nothing.png'" alt="">
</a>      ##从leftImg里面的img获取src图片1
</div>
<div class="CentTxt">
<h3 class="rightTxtHead">
<a href="/site_www.baidu.com.html" title="百度" target="_blank" class="pr10 fz14">百度</a> ##从rightTxtHead中的pr10 fz14获取百度
<span class="col-gray">www.baidu.com</span>  ####从rightTxtHead中的col-gray获取www.baidu.com
</h3>
div class="RtCPart clearfix">
<p class="RtCData">
<span>Alexa周排名:</span>
<a target="_blank" href="//alexa.chinaz.com/www.baidu.com">4</a> ##从RtCData里的a中获得4
</p>
<p class="RtCData">  
<span>百度权重为:</span>           ##从RtCData中的a的img获得/images/baidu/9.gif
<a target="_blank" href="//rank.chinaz.com/www.baidu.com"><img src="/images/baidu/9.gif"></a>
</p>                        ##同理
<p class="RtCData"><span>PR:</span><a target="_blank" href="//pr.chinaz.com/?PRAddress=www.baidu.com"><img src="/images/ranks/Rank_9.gif"></a></p>
<p class="RtCData"><span>反链数:</span><a target="_blank" href="//outlink.chinaz.com/?h=www.baidu.com">345762</a></p>
</div>
<p class="RtCInfo">网站简介:百度,全球大的中文搜索引擎、大的中文网站。2000年1月创立于北京中关村。...</p>
</div>
<div class="RtCRateWrap">
<div class="RtCRateCent">
<strong class="col-red02">1</strong>
<span>得分:4999</span>
</div>
</div>
</li>

Ⅰ、获取第一个网页的图片和文本:

观察发现,所需要获取的数据都在ul的 class=“listCentent” 标签下,且该class名是唯一的,所以可以直接用find定位到该ul,然后通过find_all定位到集合了30个网站排名的li列表;

用成员循环遍历该列表,在每次的循环中,先通过定位img获取得到图片数量为3的列表,根据下标顺序指定0和2即得到了目标数据;

然后对于网站名,它的a标签对应的class名pr10 fz14也是唯一的,所以可以通过find直接定位到;

剩下的三个文本信息都在p标签下,且class名都为RtCData,所以直接find_all定位得到列表,然后再获得目标数据.

Ⅱ、文件目录的创建和写入:

对于PNG目录,需要在爬虫启动前先用文件路径定位获取当前路径然后创建该目录,图片的写入则需要加上文件的名,利用计数器和format格式对文件名进行命名写入,每次程序启动时都需要判断PNG目录是否存在,存在则删除,提高程序的可执行性.

对于文本文件的创建直接open就行,需要使用追加模式,不然每次循环都会覆盖前一次的写入,删除也可以提前进行判断.

Ⅲ、mysql的连接和写入

conn=pymysql.connect(

host=‘192.168.1.111’, #linux对应的ip地址

user=‘root’, #mysql的用户名

passwd=‘root’, #mysql的登入密码

db=‘test’, #mysql的数据库

port=3306 #mysql的端号

)

cursor=conn.cursor() #创建游标

cursor.execute(

“insert into webs(name,web,AleaxaRank,ReChainNum,img_src1,img_src2)values(%s,%s,%s,%s,%s,%s)”,

(str(name),str(web),str(AleaxaRank),str(ReChainNum),str(img_src1),str(img_src2))

) #insert的前提是你mysql里面有webs这个表了,没有的话需要创建create table webs(name varchar(50),web varchar(50),AleaxaRank varchar(50),ReChainNum varchar(50),img_src1 varchar(200),img_src2 varchar(200)),这里为什么建议你在mysql上执行呢,因为每次程序执行时你已经存在了该库就报错了,当然你也可以先判断,或者用完第一次就注释掉.

conn.commit()#提交

Ⅳ、网站翻页和网址不全的解决办法

 <div class="ListPageWrap">
            <a href="/hangye/index.html" > 
            < </a><a class="Pagecurt"href="/hangye/index.html">1</a>
            <a href="/hangye/index_2.html">2</a>
            <a href="/hangye/index_3.html">3</a>
            <a href="/hangye/index_4.html">4</a>
            <a href="/hangye/index_5.html">5</a>
            <a href="/hangye/index_6.html">6</a>
            <a href="/hangye/index_7.html">7</a>
            <a href="/hangye/index_8.html">8</a>
            <span>...</span>
            <a href="/hangye/index_1872.html">1872</a>
            <a href="/hangye/index_2.html"> > </a>
        </div>

找到翻页对应的html代码,发现div对应的class”ListPageWrap”名是唯一的,所以可以直接find定位得到,然后再find_all得到a的列表集合,利用for循环得到每个网页的网址.

你也可以观察发现,该网页的跳转都是由规律的都是index_后面的数字+1,所以你可以用for循环和format格式来拼接字符串得到网站.

对于获取href或者src网址不全的问题,我们可以通过观察如果它是有规律的,那就进行拼接字符串,如果没有规律,只能通过模拟点击的方式来实现.



四、Mysql查看结果

mysql -uroot -proot

use test;

select * from webs;

在这里插入图片描述



版权声明:本文为weixin_56115549原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。