spider-02
发布日期:2021-06-29 12:07:03 浏览次数:3 分类:技术文章

本文共 15867 字,大约阅读时间需要 52 分钟。

文章目录

spider-day02笔记

数据持久化 - MySQL

  • pymysql回顾

    import pymysqldb = pymysql.connect('localhost','root','123456','maoyandb',charset='utf8')cursor = db.cursor()ins = 'insert into filmtab values(%s,%s,%s)'cursor.execute(ins,['霸王别姬','张国荣','1993'])db.commit()cursor.close()db.close()

数据持久化 - MongoDB

  • MongoDB特点

    【1】非关系型数据库,数据以键值对方式存储,端口27017【2】MongoDB基于磁盘存储【3】MongoDB数据类型单一,值为JSON文档,而Redis基于内存,   3.1> MySQL数据类型:数值类型、字符类型、日期时间类型、枚举类型   3.2> Redis数据类型:字符串、列表、哈希、集合、有序集合   3.3> MongoDB数据类型:值为JSON文档【4】MongoDB: 库 -> 集合 -> 文档     MySQL  : 库 -> 表  ->  表记录
  • MongoDB常用命令

    Linux进入: mongo>show dbs                  - 查看所有库>use 库名                   - 切换库>show collections          - 查看当前库中所有集合>db.集合名.find().pretty()  - 查看集合中文档>db.集合名.count()          - 统计文档条数>db.集合名.drop()           - 删除集合>db.dropDatabase()         - 删除当前库
  • pymongo模块使用

    import pymongo# 1.连接对象conn = pymongo.MongoClient(host = 'localhost',port = 27017)# 2.库对象db = conn['maoyandb']# 3.集合对象myset = db['maoyanset']# 4.插入数据库myset.insert_one({
    'name':'赵敏'})
  • 练习 - 将电影信息存入MongoDB数据库

    """猫眼电影top100抓取(电影名称、主演、上映时间)存入mongodb数据库中"""import requestsimport reimport timeimport randomimport pymongoclass MaoyanSpider:    def __init__(self):        self.url = 'https://maoyan.com/board/4?offset={}'        self.headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36'} # 三个对象:连接对象、库对象、集合对象 self.conn = pymongo.MongoClient('127.0.0.1', 27017) self.db = self.conn['maoyandb'] self.myset = self.db['maoyanset2'] def get_html(self, url): html = requests.get(url=url, headers=self.headers).text # 直接调用解析函数 self.parse_html(html) def parse_html(self, html): """解析提取数据""" regex = '
    .*?title="(.*?)".*?

    (.*?)

    .*?

    (.*?)

    ' pattern = re.compile(regex, re.S) r_list = pattern.findall(html) # r_list: [('活着','牛犇','2000-01-01'),(),(),...,()] self.save_html(r_list) def save_html(self, r_list): """数据处理函数""" for r in r_list: item = {
    } item['name'] = r[0].strip() item['star'] = r[1].strip() item['time'] = r[2].strip() print(item) # 存入到mongodb数据库 self.myset.insert_one(item) def run(self): """程序入口函数""" for offset in range(0, 91, 10): url = self.url.format(offset) self.get_html(url=url) # 控制数据抓取频率:uniform()生成指定范围内的浮点数 time.sleep(random.uniform(0,1))if __name__ == '__main__': spider = MaoyanSpider() spider.run()

数据持久化 - csv

  • csv描述

    【1】作用   将爬取的数据存放到本地的csv文件中【2】使用流程    2.1> 打开csv文件    2.2> 初始化写入对象    2.3> 写入数据(参数为列表)   【3】示例代码    import csv     with open('sky.csv','w') as f:        writer = csv.writer(f)        writer.writerow([])
  • 示例

    【1】题目描述    创建 test.csv 文件,在文件中写入数据【2】数据写入 - writerow([])方法    import csv    with open('test.csv','w') as f:  # with open('test.csv','w',newline='') as f:----->windows里面的写法,因为再wiondows中每条数据会有一个空行 	    writer = csv.writer(f)	    writer.writerow(['超哥哥','25'])
  • 练习 - 使用 writerow() 方法将猫眼电影数据存入本地 maoyan.csv 文件

    【1】在 __init__() 中打开csv文件,因为csv文件只需要打开和关闭1次即可【2】在 save_html() 中将所抓取的数据处理成列表,使用writerow()方法写入【3】在run() 中等数据抓取完成后关闭文件
  • 代码实现

    """猫眼电影top100抓取(电影名称、主演、上映时间)存入csv文件,使用writerow()方法"""import requestsimport reimport timeimport randomimport csvclass MaoyanSpider:    def __init__(self):        self.url = 'https://maoyan.com/board/4?offset={}'        self.headers = {
    'User-Agent':'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)'} # 打开文件,初始化写入对象 self.f = open('maoyan.csv', 'w', newline='', encoding='utf-8') self.writer = csv.writer(self.f) def get_html(self, url): html = requests.get(url=url, headers=self.headers).text # 直接调用解析函数 self.parse_html(html) def parse_html(self, html): """解析提取数据""" regex = '
    .*?title="(.*?)".*?

    (.*?)

    .*?

    (.*?)

    ' pattern = re.compile(regex, re.S) r_list = pattern.findall(html) # r_list: [('活着','牛犇','2000-01-01'),(),(),...,()] self.save_html(r_list) def save_html(self, r_list): """数据处理函数""" for r in r_list: li = [ r[0].strip(), r[1].strip(), r[2].strip() ] self.writer.writerow(li) print(li) def run(self): """程序入口函数""" for offset in range(0, 91, 10): url = self.url.format(offset) self.get_html(url=url) # 控制数据抓取频率:uniform()生成指定范围内的浮点数 time.sleep(random.uniform(1,2)) # 所有数据抓取并写入完成后关闭文件 self.f.close()if __name__ == '__main__': spider = MaoyanSpider() spider.run()

useragent 池

sudo pip3 install fake_useragent		# 爬虫生成useragent的插件,大概有250个UserAgentfrom fake_useragent import UserAgenthearders = {
'User-Agent': UserAgent().random}

汽车之家数据抓取 - 二级页面

  • 领取任务

    【1】爬取地址    汽车之家 - 二手车 - 价格从低到高    https://www.che168.com/beijing/a0_0msdgscncgpi1lto1csp1exx0/  【2】爬取目标    所有汽车的 型号、行驶里程、上牌时间、档位、排量、车辆所在地、价格【3】爬取分析    *********一级页面需抓取***********        1、车辆详情页的链接            *********二级页面需抓取***********        1、名称        2、行驶里程        3、上牌时间        4、档位        5、排量        6、车辆所在地        7、价格
  • 实现步骤

    【1】确定响应内容中是否存在所需抓取数据 - 存在【2】找URL地址规律    第1页: https://www.che168.com/beijing/a0_0msdgscncgpi1lto1csp1exx0/    第2页: https://www.che168.com/beijing/a0_0msdgscncgpi1lto1csp2exx0/    第n页: https://www.che168.com/beijing/a0_0msdgscncgpi1lto1csp{
    }exx0/ 【3】 写正则表达式 一级页面正则表达式:
  • 二级页面正则表达式:
    .*?

    (.*?)

    .*?
      .*?
    • .*?

      (.*?)

      .*?

      (.*?)

      .*?

      (.*?)

      .*?

      (.*?)

      .*?¥(.*?)【4】代码实现
  • 代码实现

    """汽车之家二手车信息抓取思路    1、一级页面:汽车的链接    2、二级页面:具体汽车信息建立User-Agent池:防止被网站检测到是爬虫    使用fake_useragent模块    安装:sudo pip3 install fake_useragent    使用:        from fake_useragent import UserAgent        UserAgent().random"""import requestsimport reimport timeimport randomfrom fake_useragent import UserAgentclass CarSpider:    def __init__(self):        self.url = 'https://www.che168.com/beijing/a0_0msdgscncgpi1lto1csp{}exx0/'    def get_html(self, url):        """功能函数1 - 获取html"""        headers = {
    'User-Agent':UserAgent().random } html = requests.get(url=url, headers=headers).text return html def re_func(self, regex, html): """功能函数2 - 正则解析函数""" pattern = re.compile(regex, re.S) r_list = pattern.findall(html) return r_list def parse_html(self, one_url): """爬虫逻辑函数""" one_html = self.get_html(url=one_url) one_regex = '
  • ' href_list = self.re_func(regex=one_regex, html=one_html) for href in href_list: two_url = 'https://www.che168.com' + href # 获取1辆汽车的具体信息 self.get_car_info(two_url) # 控制爬取频率 time.sleep(random.randint(1,2)) def get_car_info(self, two_url): """获取1辆汽车的具体信息""" two_html = self.get_html(url=two_url) two_regex = '
    .*?

    (.*?)

    .*?

    (.*?)

    .*?

    (.*?)

    .*?

    (.*?)

    .*?

    (.*?)

    .*?
    ¥(.*?)' # car_list: [('福睿斯','3万公里','2016年3月','手动 / 1.5L', '廊坊', '5.60'),] car_list = self.re_func(regex=two_regex, html=two_html) item = {
    } item['name'] = car_list[0][0].strip() item['km'] = car_list[0][1].strip() item['time'] = car_list[0][2].strip() item['type'] = car_list[0][3].split('/')[0].strip() item['displace'] = car_list[0][3].split('/')[1].strip() item['address'] = car_list[0][4].strip() item['price'] = car_list[0][5].strip() print(item) def run(self): for i in range(1,5): url = self.url.format(i) self.parse_html(url)if __name__ == '__main__': spider = CarSpider() spider.run()
  • 练习 - 将数据存入MySQL数据库

    create database cardb charset utf8;use cardb;create table cartab(name varchar(100),km varchar(50),years varchar(50),type varchar(50),displacement varchar(50),city varchar(50),price varchar(50))charset=utf8;

使用redis实现增量爬虫

"""提示: 使用redis中的集合,sadd()方法,添加成功返回1,否则返回0请各位大佬忽略掉下面代码,自己独立实现"""import requestsimport reimport timeimport randomimport pymysqlfrom hashlib import md5import sysimport redisclass CarSpider(object):  def __init__(self):      self.url = 'https://www.che168.com/beijing/a0_0msdgscncgpi1lto1csp{}exx0/'      self.headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'} self.db = pymysql.connect('localhost','root','123456','cardb',charset='utf8') self.cursor = self.db.cursor() # 连接redis去重 self.r = redis.Redis(host='localhost',port=6379,db=0) # 功能函数1 - 获取响应内容 def get_html(self,url): html = requests.get(url=url,headers=self.headers).text return html # 功能函数2 - 正则解析 def re_func(self,regex,html): pattern = re.compile(regex,re.S) r_list = pattern.findall(html) return r_list # 爬虫函数开始 def parse_html(self,one_url): one_html = self.get_html(one_url) one_regex = '
  • ' href_list = self.re_func(one_regex,one_html) for href in href_list: # 加密指纹 s = md5() s.update(href.encode()) finger = s.hexdigest() # 如果指纹表中不存在 if self.r.sadd('car:urls',finger): # 每便利一个汽车信息,必须要把此辆汽车所有数据提取完成后再提取下一辆汽车信息 url = 'https://www.che168.com' + href # 获取一辆汽车的信息 self.get_data(url) time.sleep(random.randint(1,2)) else: sys.exit('抓取结束') # 获取一辆汽车信息 def get_data(self,url): two_html = self.get_html(url) two_regex = '
    .*?

    (.*?)

    .*?
      .*?
    • .*?

      (.*?)

      .*?

      (.*?)

      .*?

      (.*?)

      .*?

      (.*?)

      .*?¥(.*?)
  • xpath解析

    • 定义

      XPath即为XML路径语言,它是一种用来确定XML文档中某部分位置的语言,同样适用于HTML文档的检索
    • 匹配演示 - 猫眼电影top100

      【1】查找所有的dd节点    //dd【2】获取所有电影的名称的a节点: 所有class属性值为name的a节点    //p[@class="name"]/a【3】获取dl节点下第2个dd节点的电影节点    //dl[@class="board-wrapper"]/dd[2]                          【4】获取所有电影详情页链接: 获取每个电影的a节点的href的属性值    //p[@class="name"]/a/@href【注意】                                 1> 只要涉及到条件,加 [] : //dl[@class="xxx"]   //dl/dd[2]    2> 只要获取属性值,加 @  : //dl[@class="xxx"]   //p/a/@href
    • 选取节点

      【1】// : 从所有节点中查找(包括子节点和后代节点)【2】@  : 获取属性值  2.1> 使用场景1(属性值作为条件)       //div[@class="movie-item-info"]  2.2> 使用场景2(直接获取属性值)       //div[@class="movie-item-info"]/a/img/@src    【3】练习 - 猫眼电影top100  3.1> 匹配电影名称      //div[@class="movie-item-info"]/p[1]/a/@title  3.2> 匹配电影主演      //div[@class="movie-item-info"]/p[2]/text()  3.3> 匹配上映时间      //div[@class="movie-item-info"]/p[3]/text()  3.4> 匹配电影链接      //div[@class="movie-item-info"]/p[1]/a/@href
    • 匹配多路径(或)

      xpath表达式1 | xpath表达式2 | xpath表达式3
    • 常用函数

      【1】text() :获取节点的文本内容    xpath表达式末尾不加 /text() :则得到的结果为节点对象    xpath表达式末尾加 /text() 或者 /@href : 则得到结果为字符串        【2】contains() : 匹配属性值中包含某些字符串节点    匹配class属性值中包含 'movie-item' 这个字符串的 div 节点     //div[contains(@class,"movie-item")]
    • 终极总结

      【1】字符串: xpath表达式的末尾为: /text() 、/@href  得到的列表中为'字符串' 【2】节点对象: 其他剩余所有情况得到的列表中均为'节点对象'     [
      ,
      ,
      ] [
      ,
      ] [
      ,
      ,
      ]
    • 课堂练习

      【1】匹配汽车之家-二手车,所有汽车的链接 :     //li[@class="cards-li list-photo-li"]/a[1]/@href    //a[@class="carinfo"]/@href【2】匹配汽车之家-汽车详情页中,汽车的     2.1)名称:  //div[@class="car-box"]/h3/text()     2.2)里程:  //ul/li[1]/h4/text()     2.3)时间:  //ul/li[2]/h4/text()     2.4)挡位+排量: //ul/li[3]/h4/text()     2.5)所在地: //ul/li[4]/h4/text()     2.6)价格:   //div[@class="brand-price-item"]/span[@class="price"]/text()

    lxml解析库

    • 安装

      【1】Ubuntu:  sudo pip3 install lxml【2】Windows: python -m pip install lxml
    • 使用流程

      1、导模块   from lxml import etree2、创建解析对象   parse_html = etree.HTML(html)3、解析对象调用xpath   r_list = parse_html.xpath('xpath表达式')
    • xpath最常用

      【1】基准xpath: 匹配所有电影信息的节点对象列表   //dl[@class="board-wrapper"]/dd   [
      ,
      ,...] 【2】遍历对象列表,依次获取每个电影信息 item = {
      } for dd in dd_list: item['name'] = dd.xpath('.//p[@class="name"]/a/text()').strip() item['star'] = dd.xpath('.//p[@class="star"]/text()').strip() item['time'] = dd.xpath('.//p[@class="releasetime"]/text()').strip()
    • 猫眼电影案例-xpath实现

      """猫眼电影top100抓取(电影名称、主演、上映时间)"""import requestsimport timeimport randomfrom lxml import etreeclass MaoyanSpider:    def __init__(self):        self.url = 'https://maoyan.com/board/4?offset={}'        self.headers = {
      'User-Agent':'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)'} def get_html(self, url): html = requests.get(url=url, headers=self.headers).text # 直接调用解析函数 self.parse_html(html) def parse_html(self, html): """解析提取数据 - xpath""" p = etree.HTML(html) # 基准xpath:每个电影信息的节点对象dd列表 [
      ,
      ,...] dd_list = p.xpath('//dl[@class="board-wrapper"]/dd') print(dd_list) item = {
      } for dd in dd_list: item['name'] = dd.xpath('.//p[@class="name"]/a/@title')[0].strip() item['star'] = dd.xpath('.//p[@class="star"]/text()')[0].strip() item['time'] = dd.xpath('.//p[@class="releasetime"]/text()')[0].strip() print(item) def run(self): """程序入口函数""" for offset in range(0, 91, 10): url = self.url.format(offset) self.get_html(url=url) # 控制数据抓取频率:uniform()生成指定范围内的浮点数 time.sleep(random.uniform(0,1))if __name__ == '__main__': spider = MaoyanSpider() spider.run()
    • 小作业

      汽车之家案例使用lxml+xpath实现

      Day02回顾

    数据抓取

    • 思路步骤

      【1】先确定是否为动态加载网站【2】找URL规律【3】正则表达式 | xpath表达式【4】定义程序框架,补全并测试代码
    • 多级页面数据抓取思路

      【1】整体思路    1.1> 爬取一级页面,提取 所需数据+链接,继续跟进    1.2> 爬取二级页面,提取 所需数据+链接,继续跟进    1.3> ... ... 【2】代码实现思路    2.1> 避免重复代码 - 请求、解析需定义函数
    • 增量爬虫实现思路

      【1】原理    利用Redis集合特性,可将抓取过的指纹添加到redis集合中,根据返回值来判定是否需要抓取	返回值为1 : 代表之前未抓取过,需要进行抓取	返回值为0 : 代表已经抓取过,无须再次抓取    【2】代码实现模板import redisfrom hashlib import md5import sysclass XxxIncrSpider:  def __init__(self):    self.r = redis.Redis(host='localhost',port=6379,db=0)      def url_md5(self,url):    """对URL进行md5加密函数"""    s = md5()    s.update(url.encode())    return s.hexdigest()    def run_spider(self):    href_list = ['url1','url2','url3','url4']    for href in href_list:      href_md5 = self.url_md5(href)      if self.r.sadd('spider:urls',href_md5) == 1:        返回值为1表示添加成功,即之前未抓取过,则开始抓取      else:        sys.exit()
    • 目前反爬处理

      【1】基于User-Agent反爬	1.1) 发送请求携带请求头: headers={
      'User-Agent' : 'Mozilla/5.0 xxxxxx'} 1.2) 多个请求时随机切换User-Agent a) 定义py文件存放大量User-Agent,导入后使用random.choice()每次随机选择 b) 使用fake_useragent模块每次访问随机生成User-Agent from fake_useragent import UserAgent agent = UserAgent().random 【2】响应内容存在特殊字符 解码时使用ignore参数 html = requests.get(url=url, headers=headers).content.decode('', 'ignore')

    数据持久化

    • csv

      import csv with open('xxx.csv','w',encoding='utf-8',newline='') as f:	writer = csv.writer(f) 	writer.writerow([])
    • MySQL

      import pymysql# __init__(self):	self.db = pymysql.connect('IP',... ...)	self.cursor = self.db.cursor()	# save_html(self,r_list):	self.cursor.execute('sql',[data1])	self.db.commit()	# run(self):	self.cursor.close()	self.db.close()
    • MongoDB

      import pymongo# __init__(self):	self.conn = pymongo.MongoClient('IP',27017)	self.db = self.conn['cardb']	self.myset = self.db['car_set']	# save_html(self,r_list):	self.myset.insert_one(dict)# MongoDB - Commmand - 库->集合->文档mongo>show dbs>use db_name>show collections>db.集合名.find().pretty()>db.集合名.count()>db.集合名.drop()>db.dropDatabase()

    xpath表达式

    • 匹配规则

      【1】结果: 节点对象列表   1.1) xpath示例: //div、//div[@class="student"]、//div/a[@title="stu"]/span【2】结果: 字符串列表   2.1) xpath表达式中末尾为: @src、@href、/text()

    转载地址:https://blog.csdn.net/z_202041/article/details/117944849 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

    上一篇:spider-03
    下一篇:technology

    发表评论

    最新留言

    关注你微信了!
    [***.104.42.241]2024年04月29日 07时12分58秒