学习笔记


爬取X度某吧里的小图片们

写个小案例,获取X度里,你指定的吧里,第kkk页之前所有帖子内的图片,当然这个kkk由你定。

爬取步骤

①获取用户指定吧名指定页数,得到贴吧主页URL。

②获取1页中所有帖子URL地址,并获取本吧的最大页数。

③for循环每个帖子的URL地址,对每个帖子链接发请求

④获取一个帖子的最大页数,遍历帖子内所有页里的图片

⑤拿到图片的链接后,获取图片以wb的形式,保存到mysql数据库。

⑥第1页处理完后,再处理第2页,以此类推…直到处理到用户指定页面数。

总结一下!我们需要用Xpath获取贴吧内帖子的url,帖子内所有图片的url;
并且用正则表达式匹配某个吧内的最大页数,一个帖子内的最大页数。

URL特征

  • 同一个吧内不同页面URL地址特征

第二页:

https://tieba.baidu.com/f?kw=%E5%85%94%E5%AD%90&ie=utf-8&pn=50

第三页:

https://tieba.baidu.com/f?kw=%E5%85%94%E5%AD%90&ie=utf-8&pn=100

可以看到查询参数pn在第2页为50,第3页为100,则可以推断此处的pn参数可以控制页数,且第kkk页pn=(k−1)∗50pn=(k-1)*50pn=(k−1)∗50。

同时,我们判断kw参数后是吧名的ASCII编码值,我们将其转换为中文字符,验证一下:

嗯!是的呢~

  • 同一个帖子内不同页面URL特征

第二页:

https://tieba.baidu.com/p/6554079192?pn=2

第三页:

https://tieba.baidu.com/p/6554079192?pn=3

可以看到查询参数pn在第2页为2,第3页为3,则可以推断此处的pn参数可以控制页数,且第kkk页pn=kpn=kpn=k

Xpath表达式

在这里我就不放页面源代码进行HTML页面分析了,因为写这个Blog的时候有点晚了,不想贴太多图片了,脑子也转不动了,而且也有某个红领巾帮我写好Xpath了。

这个红领巾是谁呢?我们右键点击网页,选择【审查元素】–>选中要获取的页面信息,再右键选择【Copy】–>最后选择【Copy Xpath】! 这样就得到Xpath表达式啦!

O_o…wc, 要是那么简单就可以获取Xpath表达式了,我之前还花了1天时间写了一系列Xpath总结???心碎…

比如,我想获取如下帖子的URL地址:

通过Copy Xpath,看一看这个红领巾帮我们获取的Xpath:

//*[@id="thread_list"]/li[1]/div/div[2]/div[1]/div[1]/a

在用Chrome插件Xpath Helper检查一下,看看匹配到了啥:

可以看到只匹配到了1个结果,而且还不是帖子链接,只是帖子文本!但是我们想要的是匹配50个帖子链接,所以,这个红领巾给的Xpath表达式"不怎么合格"。虽然这个表达式不怎么合格,但是它给了我们一些提示,我们可以按照红领巾给我们的Xpath表达式逻辑,来写出符合要求的合格表达式。

这里就不具体写咋获取合格Xpath表达式的具体步骤了。

直接放修改后的Xpath表达式(注意,Xpath表达式中最好不要带位置谓词,但是可以写带属性的谓词):

//*[@id="thread_list"]/li//div[@class="t_con cleafix"]/div/div/div/a/@href

在Xpath Helper中检查一下:

perfect! (需要注意的是,这个Xpath表达式,是参考别人的,我自己写了一个表达式,用Xpath Helper可以匹配到URL,但是在python中就匹配不到了,心累!不知道为啥,这里标记一下,以后深入学习后,再回来解决)

备注:不要过度加谓词(条件),这样可能会导致一些数据的丢失。

图片链接的URL我们也可以试着用这种方式获取,这里也不详述了,直接给Xpath表达式:

//img[@class="BDE_Image"]/@src

正则表达式

贴吧最大页数正则表达式:

下一页.*?<a href=.*?&pn=(\d*?)".*?>尾页</a>

帖子内页面总数正则表达式:

<li class="l_reply_num".*?回复贴,共.*?<span class="red">(\d*?)</span>页</li>

mysql内创建存储图片数据的数据库

在敲python代码之前,我们先建一个mysql数据库,等下爬虫时,存放我们的图片信息。

use datacup;
create table ba_image_table(id int primary key auto_increment,
ba_name varchar(30) not null,
image_url varchar(200) default "None",
image_data mediumblob);

python代码与mysql操作

注意,下面代码中的my_user_agent_list是我的自定义模块,里面是专门放User-Agent的列表。

代码:

# -*- coding: utf-8 -*-import requests
from lxml import etree
import pymysql
import random
import time
from urllib import parse
from my_user_agent_list import user_agent
import math
import reclass PagenumError(Exception):def __init__(self, msg, page_value):super().__init__(msg)self.page_value = page_valueclass BaNameError(Exception):def __init__(self, msg):super().__init__(msg)class TiebaSpider:def __init__(self):self.url = 'http://tieba.baidu.com/f?kw={}&pn={}'self.user_agent = user_agentself.page = 1self.db = pymysql.connect(host = '127.0.0.1',port = 3306,user = 'root',password = '19970928',database = 'datacup',charset = 'utf8')self.cur = self.db.cursor()#获取html页面def get_page(self, url):try:res = requests.get(url, headers = {'User-Agent':random.choice(self.user_agent)})test_url = res.urlprint(test_url)if not self.url_exist(test_url):raise BaNameError('请检查输入贴吧是否存在是否正确...')        #print(res.url)except BaNameError as e:print(e.args)http_status_code = -1html = 'None'except Exception as e:print('连接错误,未知错误')http_status_code = -1html = 'None'else:html = res.content.decode('utf-8')#print(html)http_status_code = res.status_codeprint(http_status_code)return (http_status_code, html)#解析HTML页面,拿到该页面所有帖子链接和全部图片def parse_page(self, html):parse_html = etree.HTML(html)li_xpath = '//*[@id="thread_list"]/li//div[@class="t_con cleafix"]/div/div/div/a/@href'#拿链接,去广告li_list = parse_html.xpath(li_xpath)#print('本页帖子数:', len(li_list))li_list = ["http://tieba.baidu.com"+item for item in li_list if re.findall(r'^/p', item)]print('本页帖子数:', len(li_list))image_matrtix = []for item in li_list:image_list = self.parse_two_page(item)image_matrtix.append(image_list)return sum(image_matrtix, [])#获取帖子内的图片URLdef parse_two_page(self, url):(http_status_code, html) = self.get_page(url)page_num = self.get_page_num(html, url)image_xpath = '//img[@class="BDE_Image"]/@src'image_list = []for item in range(1, page_num + 1):temp_url = url + "/?pn={}".format(item)print("帖子url:", temp_url)(http_status_code, html) = self.get_page(temp_url)parse_html = etree.HTML(html)image = parse_html.xpath(image_xpath)print('本页图片数:', len(image))image_list.append(image)return sum(image_list, [])#图片下载def downloads_image(self, url_list, ba_name):data_list = []for url in url_list:image_data = requests.get(url, headers = {'User-Agent':random.choice(self.user_agent)}).contentdata_list.append((ba_name, url, image_data))self.write_page(data_list)      #写出数据def write_page(self, data_list):sql = 'insert into ba_image_table(ba_name, image_url, image_data) \values(%s, %s, %s);'try:self.cur.executemany(sql, data_list)self.db.commit()except Exception as e:self.db.rollback()print('错误信息:', e)#判断吧是否存在def url_exist(self, url):#若不存在该吧,则返回Falseif r'search/res' in url:idcard = Falseelse:idcard = Truereturn idcard#页面控制def get_page_num(self, html, url):if r'f?kw' in url:regex01 =  r'下一页.*?<a href=.*?&pn=(\d*?)".*?>尾页</a>'pattern = re.compile(regex01, re.S)page_list = pattern.findall(html)print('情况1:', page_list)if not page_list:page_max = 1else:temp_num = int((int(page_list[0])/50) + 1) page_max = temp_numelse:regex02 =  r'<li class="l_reply_num".*?回复贴,共.*?<span class="red">(\d*?)</span>页</li>'pattern = re.compile(regex02, re.S)page_list = pattern.findall(html)print('情况2:',page_list)if not page_list:page_max = 1else:page_max = int(page_list[0])print('本吧目前有{}页'.format(page_max))return page_max#主函数def main(self):while True:this_page = 1ba_name = input('输入要爬取的吧名(比如:兔子,末尾不用加"吧"字):')ba_name = parse.quote(ba_name)url = self.url.format(ba_name, 0)print(url)(http_status_code, html) = self.get_page(url)if http_status_code == -1:qtx = input('是否退出(q),不退出则再查询一次(c):')if qtx == 'q':breakelse:continuecount_inpute_page = 0while True:count_inpute_page +=1try:my_page = math.ceil(int(input('输入查询页数:'))) if my_page <= 0:raise PagenumError('为非正数', my_page)except ValueError as e1:print('输入的不是数值')except PagenumError as e2:print('错误信息:', e2.page_value, e2.args[0])except Exception as e:print('未知错误...')print(e.args)else:breakif count_inpute_page >= 3:qtx = input('是否退出,若退出,只查询第1页信息(q):')if qtx == 'q':my_page = 1breakurl = self.url.format(ba_name, 0)page_num = self.get_page_num(html, url)in_ba_name = parse.unquote(ba_name)if my_page <= page_num:page_num = my_pagefor page in range(1, page_num + 1):page = (page-1)*50url = self.url.format(ba_name,page)print(url)(http_status_code, html) = self.get_page(url)print(http_status_code)image_url_list = self.parse_page(html)self.downloads_image(image_url_list, in_ba_name)print('共爬取%d次' % self.page)print('本次爬取%d页' % this_page)self.page += 1this_page += 1time.sleep(random.randint(1, 3))qtx = input('本次查询完成,是否退出(q),不退出则再查询一次(c):')if qtx == 'q':breakself.cur.close()self.db.close()if __name__ == '__main__':start = time.time()spider = TiebaSpider()spider.main()end = time.time()print('执行时间:%.2f' % (end-start))

控制台输出(部分):

入要爬取的吧名(比如:兔子,末尾不用加"吧"字):兔子
http://tieba.baidu.com/f?kw=%E5%85%94%E5%AD%90&pn=0
https://tieba.baidu.com/f?kw=%E5%85%94%E5%AD%90&pn=0
200输入查询页数:1
情况1: ['416050']
本吧目前有8322页
http://tieba.baidu.com/f?kw=%E5%85%94%E5%AD%90&pn=0
https://tieba.baidu.com/f?kw=%E5%85%94%E5%AD%90&pn=0
200
200
本页帖子数: 50
本页帖子数(排除后): 50
https://tieba.baidu.com/p/6538986625?red_tag=2049280356
200
情况2: ['1', '1']
本吧目前有1页
帖子url: http://tieba.baidu.com/p/6538986625/?pn=1
https://tieba.baidu.com/p/6538986625/?pn=1&red_tag=1684499831
200
本页图片数: 8
https://tieba.baidu.com/p/6549848737?red_tag=2051121165
200

Mysql图片导出

我们在Mysql Workbench看一下,利用python爬虫的结果是否导入了数据库中。

sql执行指令及过程:

16:42:08 select * from ba_image_table LIMIT 0, 1000  533 row(s) returned 0.015 sec / 4.110 sec

数据表显示(部分):

可以看到数据已经导入了,第一个字段为id号,第二个为吧名,第三个为图片地址,第四个为图片的二进制形式数据。

现在我们利用python读取一个图片数据,并显示出来。

python代码:

# -*- coding: utf-8 -*-import pymysqldb = pymysql.connect(host = '127.0.0.1',port = 3306,user = 'root',password = '19970928',database = 'datacup',charset = 'utf8')
cur = db.cursor()sql = "select image_url,image_data from ba_image_table where id=820;"
cur.execute(sql)
(url, data) =  cur.fetchone()
print(url)
with open('test/Bunny_image_0408.jpg', 'wb') as f:f.write(data)cur.close()
db.close()

控制台输出:

http://tiebapic.baidu.com/forum/w%3D580/sign=26386e88e5d3572c66e29cd4ba126352/f97fd7ca7bcb0a46def6b2587c63f6246a60af03.jpg

爬取到的图片:

嗯!不错,这个案例就算做完啦。


后记:虽然说好复试前不写爬虫的,但忍不住又写了。虽然爬到了结果,但是还需要后续进一步学习。
这里有几个问题:
问题1:有的时候程序会爬不下来,等一会再执行又可以爬下来了
问题2:最大页数通过正则匹配,因为我通过Xpath没匹配到…苍天啊,这是为啥
现在暂时不知道咋解决,这里标记一下,有待修改!

利用pyhton爬虫(案例4)--你想要的图片都在这相关推荐

  1. 利用pyhton爬虫(案例3)--X房网的小房子们

    写了个小案例,顺便复习一下以前学的知识点. PS:复试之前绝不写爬虫案例了(对于现在的我来说,费脑又花时间),再写我吃XX. 文章目录 爬取X房网二手房信息 爬取步骤 URL特征 查看HTML页面源代 ...

  2. 利用python爬虫(案例8)--今天就是吃X我也要搞到有道

    学习笔记 备注:这个Blog也是part14 爬取有道 写个案例,我想要破解有道翻译(http://fanyi.youdao.com/)接口,抓取翻译结果. 一开始,我还以为写这个不是很麻烦,因为2年 ...

  3. 利用python爬虫(案例7)--X讯招聘的小职位们

    学习笔记 爬取X讯招聘的小职位们 写个小案例,我们想爬取X讯招聘网站里处于1级页面的职位名称和处于2级页面的工作职责和工作要求.由于这个X讯招聘网站是动态加载的,所以需要抓取我们与网站进行交互时产生的 ...

  4. 利用python爬虫(案例2)--X凰的一天

    学习笔记 PS:为啥这个BLOG是案例2,但是我的BLOG里没有案例1,那是因为BLOG1被锁了.心痛. 爬取新闻标题和链接 我想通过Xpath拿到X凰X闻[http://news.ifeng.com ...

  5. 利用python爬虫(案例6+part14)--如何爬取科研数据

    学习笔记 文章目录 Ajax动态加载网站数据抓取 动态加载的类型 那么该如何抓取数据? 如何得到JSON文件的地址? 观察JSON文件URL地址的查询参数 JSON格式数据转换成python字典 如何 ...

  6. 轻松利用Python爬虫爬取你想要的数据

    网络爬虫的基本工作流程如下: 1.首先选取一部分精心挑选的种子URL. 2.将这些URL放入待抓取URL队列. 3.从待抓取URL队列中读取待抓取队列的URL,解析DNS,并且得到主机的IP,并将UR ...

  7. 利用python爬虫(案例5)--X刺代理的小IP们

    学习笔记 爬取X刺代理的小IP们 学完代理,我们发现网上找的很多免费代理IP都用不了,所以这里写一个简单的测试小案例,爬取一下某代理IP网站的免费代理IP,再遍历测试到底这些代理IP能不能用,哪些能用 ...

  8. 利用PYHTON爬虫爬取恋家网房价

    import openpyxl         # 导入处理excel文件用到的库 import requests         # 导入requests 请求库 from lxml import ...

  9. python爬虫详解(四)——使用爬虫爬取你想要的图片 类似于图片下载器【百度引擎】

    这个爬虫用的是百度引擎,后续需要爬取别的网站需要自行更改 点个赞留个关注吧!! 我们废话不多说,上代码: # -*- coding: utf-8 -*- import re import reques ...

最新文章

  1. 车模换几代了,电池什么时候换?
  2. nit计算机应用基础是考试大纲,全国计算机应用技术证书考试(NIT)考试大纲(计算机应用基础Windows XP)...
  3. 位示图 c语言程序,位示图模拟文件系统空闲快管理c语言
  4. 机器人抓取方式,值得研究。
  5. OPPO R9凭创新赢得2000万销量,成2016年热销手机
  6. RHEL4- SAMBA服务(四)在x-window下图形界面简单搭建samba服务器
  7. Weblogic12c T3 协议安全漏洞分析【CVE-2020-14645 CVE-2020-2883 CVE-2020-14645】
  8. mac 源生安装mysql_Django执行源生mysql语句实现过程解析
  9. Cracking the Coding Interview(Stacks and Queues)
  10. AOS编排语言系列教程(四):创建弹性云服务器ECS
  11. HDU2152 Fruit【母函数】
  12. 基于GPU加速的车牌识别算法体验
  13. Python 模拟Laguerre Polynomial拉盖尔多项式
  14. python如何变换环境
  15. IPv6技术精要(第2版)Rick Graziani
  16. picker-view-column自定义picker
  17. Dubbo原理简单分析
  18. 问题 K: 古罗马数字
  19. python3 简单选课系统
  20. 怎么压缩图片,电脑上压缩图片的方法

热门文章

  1. 机器学习(三十三)——价值函数的近似表示
  2. Java构建工具, ZeroC ICE, word2vec
  3. mysql sql字符串连接函数_Mysql字符串连接函数 CONCAT()与 CONCAT_WS()
  4. Java主线程等待子线程、线程池
  5. 为什么js中要用void 0 代替undefined
  6. video 标签存在的一些坑
  7. tomcat配置与优化
  8. 16位/32位中断机制比較
  9. 电脑记时----千年虫
  10. Facebook利用Home平台加速进军移动领域