首页 > 编程语言 >学习python-爬虫

学习python-爬虫

时间:2022-12-07 20:45:25浏览次数:41  
标签:xpath name python 爬虫 学习 item scrapy html article

爬虫04

1.爬虫介绍

  • python是做爬虫比较方便,很多爬虫的库。其次java、go
  • http协议
    • pc端、小程序、app
  • 模拟发送http请求,拿到返回数据然后解析出我们想要的数据,最后保存气起来。
    • requests,selenium bs4

2.request模块使用

  • 发送get请求
  • 请求地址中带数据:直接拼、params参数
  • 编码问题、url编码
  • 携带请求头:user-agent、referer
  • 携带cookie:登录后cookie、就是登录状态
    • 带在请求头中
    • 带在cookie参数中:字典、cookiejar对象
  • 发送post请求
  • 携带数据:data、json、传文件类型
  • Response对象的属性和方法
    • text
    • headers
    • cookies
    • content:文件

3.代理

  • 封ip、代理
  • 代理ip:收费
  • 开源的代理池

4.requests爬取视频

  • referer,视频地址还需要转换

5.bs4解析xml库

  • html是xml的一种

6.bs4遍历

  • .
  • 取属性
  • 取文本:text、string、strings
  • 嵌套使用
  • 父亲、兄弟,子孙...

7.bs4搜索

  • 可以和遍历连用
  • find、find_all
  • 5种搜索方式:字符串、布尔、正则、列表、方法

8.css选择器

  • 标签名
  • 类名
  • id

9.selenium

  • 控制浏览器、浏览器驱动跟浏览器版本对应
  • python操作浏览器
  • 无头浏览器
  • 等待
  • 搜索方式:find_element(by='', value='')
    • css选择器:CSS_SELECTOR
    • xpath
  • 获取cookie
    • 将cookie保存到本地
    • 打开页面,把cookie写入

10.抽屉半自动点赞

  • 使用requests发送点赞请求,需要携带cookie
  • 先使用selenium登录进去,然后拿到cookie
  • 最后用requests使用自动点赞。

一、xpath的使用

  • html中选择标签可以使用的通用方式有2种:css选择器和xpath选择

    XPath即XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言

  • 语法的简单介绍

    nodename	选取此节点的所有子节点
    / 			从根节点选取	/body/div
    //			从匹配选择当前节点,而不考虑它们的位置	//div
    .			选取当前节点
    ..			选取当前节点的父节点
    @			选取属性
    
  • 最简单的方式copy复制

doc = '''
<html>
 <head>
  <base href='http://example.com/' />
  <title>Example website</title>
 </head>
 <body>
  <div id='images'>
   <a href='image1.html' id='id_a'>Name: My image 1 <br/><img src='image1_thumb.jpg' /></a>
   <a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
   <a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
   <a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
   <a href='image5.html' class='li li-item' name='items'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
   <a href='image6.html' name='items'><span><h5>test</h5></span>Name: My image 6 <br /><img src='image6_thumb.jpg' /></a>
  </div>
 </body>
</html>
'''

from lxml import etree

html = etree.HTML(doc)
# html = etree.parse('search.html', etree.HTMLParser())
# 1.所有节点
a = html.xpath('//*')
# 2.指定节点(结果为列表)
b = html.xpath('//head')
# 3.子节点,子孙节点
c = html.xpath('//div/a')
d = html.xpath('//body/a')  # 子节点没有a则没有数据
e = html.xpath('//body//a')
# 4.父节点
aa = html.xpath('//body//a[@href="image1.html"]/..')
bb = html.xpath('//body//a[1]/..')
# 也可以这样
cc = html.xpath('//body//a[1]/parent::*')
dd = html.xpath('//body//a[1]/parent::div')
# 5.属性匹配
ee = html.xpath('//body//a[@href="image1.html"]')
# 6.文本获取 text()
ff = html.xpath('//body//a[@href="image1.html"]/text()')

# 7.属性获取 @
g = html.xpath('//body//a/@href')
gg = html.xpath('//body//a/@id')

# 8.属性多值匹配
# a标签有多个class类,直接匹配就不行,需要yogacontains
h = html.xpath('//body//a[@class="li"]')
hh = html.xpath('//body//a[@name="items"]')
i = html.xpath('//body//a[contains(@class,"li")]')
ii = html.xpath('//body//a[contains(@class, "li")]/text()')
# 多属性匹配
j = html.xpath('//body//a[contains(@class, "li")or @name="items"]')
jj = html.xpath('//body//a[contains(@class, "li") and @name="items"]/text()')

#10.按序选择
k = html.xpath('//a[2]/text()')
kk = html.xpath('//a[3]/@href')
# 取最后一个
l = html.xpath('//a[last()]/@href')
# 位置小于3
ll = html.xpath('//a[position() < 3]/@href')
# 倒数第二个
m = html.xpath('//a[last()-2]/@href')
# 节点轴选择
# 祖先节点:ancestor
# 使用了* 获取所有祖先节点
mm = html.xpath('//a/ancestor::*')
# 获取祖先节点中的div
n = html.xpath('//a/ancestor::div')
# 属性值:attribute
nn = html.xpath('//a[1]/attribute::*')
o = html.xpath('//a[1]/attribute::href')
# 直接子节点:child
oo = html.xpath('//a[1]/child::*')
# 所有子孙节点:descendant
p = html.xpath('//a[6]/descendant::*')

#当前节点之后所有节点
pp = html.xpath('//a[1]/following::*')
# q = html.xpath('//a[1]following::*[1]/@href')
# 当前节点之后同级节点:following-sibing
qq = html.xpath('//a[1]/following-sibling::*')
s = html.xpath('//a[1]/following-sibling::a')
ss = html.xpath('//a[1]/following-sibling::*[2]')
sss = html.xpath('//a[1]/following-sibling::*[2]/@href')
print(b)


二、selenium动作链

  • 网站中有些按住鼠标,滑动的效果===》滑动验证码

  • 两种形式

    • 形式一:

      actions = ActionChains(bro) # 拿到动作链对象
      actions.drag_and_drop(sourse, target) # 把动作放到动作链中,准备串行执行
      actions.perform()
      
    • 形式二:

      ActionChains(bro).click_and_hold(sourse).perform()
      distance = target.location['xxx']-sourse.location['xx']
      track = 0
      while track < distance:
          ActionChains(bro).move_by_offset(xoffset=2, yoffset=0).perform()
          track +=2
      
    import target as target
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver import ActionChains
    import time
    
    bro = webdriver.Chrome(executable_path='./chromedriver.exe')
    bro.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
    bro.implicitly_wait(10)
    
    try:
        bro.switch_to.frame('iframeResult') ## 切换到iframeResult
        sourse = bro.find_element(by=By.ID, value='draggable')
        target -= bro.find_element(by=By.ID, value='droppable')
    
        # 方式一:基于同一个动作链串行执行
        # actions = ActionChains(bro) # 拿到动作链对象
        # actions.drag_and_drop(sourse, target) # 把动作放在动作链中,准备串行执行
        # actions.perform()
    
        # 方式二:不同的动作链,每次移动的位移都不同
        ActionChains(bro).click_and_hold(sourse).perform()
        distance = target.location['x'] - sourse.location['x']
        print('目标距离源的x轴距离:', distance)
        track = 0
        while track < distance:
            ActionChains(bro).move_by_offset(xoffset=2, yoffset=0).perform()
            track += 2
            ActionChains(bro).release().perform()
            time.sleep(10)
    
    except Exception as e:
        print(e)
    finally:
        bro.close()
    
    

三、自动登录12306

from selenium import webdriver
from selenium.webdriver.common.by import By
import time
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--disable-blink-features=AutomationControlled")  # 去掉自动化控制的提示
bro = webdriver.Chrome(executable_path='./chromedriver.exe', options=options)

bro.get('https://kyfw.12306.cn/otn/resources/login.html')
bro.maximize_window()
# 12306检测到我们使用了selenium控制了浏览器,所以它的滑块出不来
bro.implicitly_wait(10)

try:
    username = bro.find_element(by=By.ID, value='J-userName')
    username.send_keys('13735760305')
    password = bro.find_element(by=By.ID, value='J-password')
    password.send_keys('xcc123')
    time.sleep(3)
    btn = bro.find_element(by=By.ID, value='J-login')
    btn.click()
    span = bro.find_element(by=By.ID, value='nc_1_n1z')

    ActionChains(bro).click_and_hold(span).perform()  # 鼠标点主
    ActionChains(bro).move_by_offset(xoffset=300, yoffset=0).perform()  # 滑动

    time.sleep(10)

except Exception as e:
    print(e)
finally:
    bro.close()

注意:

* 有的网站可以检测到使用了自动化控制所以我们需要加一行代码:options.add_argument("--disable-blink-features=AutomationControlled") 

四、打码平台使用

  • 使用打码平台自动登录``
import time

from selenium import webdriver
from selenium.webdriver.common.by import By
from chaojiying import ChaojiyingClient
from PIL import Image
bro = webdriver.Chrome(executable_path='./chromedriver.exe')
bro.get('http://www.chaojiying.com/apiuser/login/')
bro.implicitly_wait(10)
bro.maximize_window()
try:
    username = bro.find_element(by=By.XPATH, value='/html/body/div[3]/div/div[3]/div[1]/form/p[1]/input')
    password = bro.find_element(by=By.XPATH, value='/html/body/div[3]/div/div[3]/div[1]/form/p[2]/input')
    code = bro.find_element(by=By.XPATH, value='/html/body/div[3]/div/div[3]/div[1]/form/p[3]/input')
    btn = bro.find_element(by=By.XPATH, value='/html/body/div[3]/div/div[3]/div[1]/form/p[4]/input')
    username.send_keys('306334678')
    password.send_keys('lqz123')
    # 获取验证码:
    #1 整个页面截图
    bro.save_screenshot('main.png')
    # 2 使用pillow,从整个页面中截取出验证码图片 code.png
    img = bro.find_element(By.XPATH, '/html/body/div[3]/div/div[3]/div[1]/form/div/img')
    location = img.location
    size = img.size
    print(location)
    print(size)
    # 使用pillow扣除大图中的验证码
    img_tu = (int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height']))
    # # 抠出验证码
    # #打开
    img = Image.open('./main.png')
    # 抠图
    fram = img.crop(img_tu)
    # 截出来的小图
    fram.save('code.png')
    # 3 使用超级鹰破解
    chaojiying = ChaojiyingClient('306334678', 'lqz123', '937234')  # 用户中心>>软件ID 生成一个替换 96001
    im = open('code.png', 'rb').read()  # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
    print(chaojiying.PostPic(im, 1902))  # 1902 验证码类型  官方网站>>价格体系 3.4+版 print 后要加()
    res_code=chaojiying.PostPic(im, 1902)['pic_str']
    code.send_keys(res_code)
    time.sleep(5)
    btn.click()
    time.sleep(10)
except Exception as e:
    print(e)
finally:
    bro.close()

五、使用selenium爬取京东商品信息

from selenium import webdriver
from selenium.webdriver.common.by import By  # 按照什么方式查找,By.ID,By.CSS_SELECTOR
import time
from selenium.webdriver.common.keys import Keys


def get_goods(driver):
    try:
        goods = driver.find_elements(by=By.CLASS_NAME, value='gl-item')
        for good in goods:
            name = good.find_element(by=By.CSS_SELECTOR, value='.p-name em').text
            price = good.find_element(by=By.CSS_SELECTOR, value='.p-price i').text
            commit = good.find_element(by=By.CSS_SELECTOR, value='.p-commit a').text
            url = good.find_element(by=By.CSS_SELECTOR, value='.p-name a').get_attribute('href')
            img = good.find_element(by=By.CSS_SELECTOR, value='.p-img img').get_attribute('src')
            if not img:
                img ='https://'+ good.find_element(by=By.CSS_SELECTOR, value='.p-img img').get_attribute('data-lazy-img')

            print('''
            商品名字:%s
            商品价格:%s
            商品链接:%s
            商品图片:%s
            商品评论:%s
            ''' % (name, price, url, img, commit))

        button = driver.find_element(by=By.PARTIAL_LINK_TEXT, value='下一页')
        button.click()
        time.sleep(1)
        get_goods(driver)
    except Exception as e:
        print(e)


def spider(url, keyword):
    driver = webdriver.Chrome(executable_path='./chromedriver.exe')
    driver.get(url)
    driver.implicitly_wait(10)  # 使用隐式等待
    try:
        input_tag = driver.find_element(by=By.ID, value='key')
        input_tag.send_keys(keyword)
        input_tag.send_keys(Keys.ENTER)
        get_goods(driver)
    finally:
        driver.close()


if __name__ == '__main__':
    spider('https://www.jd.com/', keyword='精品内衣')

六、scrapy介绍

  • 前面学的都是模块如果是做专业的爬虫需要使用框架,类似于django:web

  • scrapy:爬虫框架

    • 做爬虫用的东西都封装好了,只需要在固定的位置上写固定的代码即可
  • scrapy:号称爬虫界的django

    • django 大而全,做web相关的它都用到
    • scrapy 大而全,做爬虫相关的它都用到
  • 介绍:

    Scrapy一个开源和协作的框架,起初为了页面的抓取(更准确来说,网络抓取)所设计的,使用它可以快速、简单、可扩展的方式从网站中提取所需的数据。但是目前Scrapy的用途十分广泛,可用于数据挖掘、监测和自动化测试等领域,也可以应用在获取API所返回的数据或通用的网络爬虫
    
  • 安装 scrapy

    * 针对mac、linux:
    	pip3 install scrapy
    * 针对win:可能会出错(看情况)
    	pip3 install scrapy
        如果安装失败可能操作系统缺少一些依赖。
        1.pip3 install wheel # 安装后,方便通过wheel文件安装软件 xx.whl
        2.pip3 insatll lxml
        3.pip3 install pyopenssl
        4.下载并安装pywin32:
        https://sourceforge.net/projects/pywin32/files/pywin32/
        5.下载twisted的wheel文件:
        http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
        6.执行pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
        7.pip3 install scrapy
    
  • 释放出scrapy 可执行文件

    • 以后使用这个创建爬虫项目===》django-admin创建django项目
  • 创建爬虫项目

    • scrapy startproject myfirstscrapy
  • 创建爬虫【django创建app】

    • scrapy genspider 项目名(爬虫名字) 爬取的地址
  • 启动爬虫

    • scrapy crawl cnblogs --nolog
  • pycharm中运行

    新建run.py
    from scrapy.cmdline import execute
    execute(['scrapy', 'crawl', 'cnblogs','--nolog'])
    

七、scrapy架构介绍

image

  • 引擎(EGINE)

    引擎负责控制系统所有组件之间的数据流,并在某些动作发生时触发事件。有关详细信息,请参照上面的数据流部分。
    
  • 调度器(SCHEDULER)

    用来接受引擎发过来的请求并压入队列中,并在引擎再次请求的时候返回,可以想象成一个URL的优先级队列,由它决定下一个要抓取的网址是什么,同时去除重复的网址
    
  • 下载器(DOWLOADER)

    用于下载网页内容并将网页内容返回给EGINE,下载器是建立在twisted这个高效的异步模型上的
    
  • 爬虫(SPIDERS)

    SPIDERS是开发人员自定义的类,用来解析responses,并且提取items或者发送新的请求
    
  • 项目管道(ITEM PIPLINES)

    在item被提取后负责处理他们,主要包括清理、验证、持久化(比如存到数据库)等操作
    
  • 下载器中间件(DOWLOADER Middlewares)

    位于Scrapy引擎和下载器之间,主要用来处理从EGINE传到DOWLOADER的请求request,已经从DOWNLOADER传到EGINE的响应responses,你可以用该中间件做一下几件事情:
    		1.设置请求,
        	2.设置cookie
            3.使用代理
            4.集成selenium
    
  • 爬虫中间件(Spider Middlewares)

    位于EGINE和SPIDERS之间,主要工作是处理SPIDERS的输入(即responses)和输出(即requests)
    

八、scrapy解析数据

  • response对象有css方法和xpath方法

    • css中写css选择器
    • xpath中写xpath选择
  • 重点1

    * xpath取文本内容
    	'.//a[contains(@class,"link-title")]/text()'
    * xpath取属性
    	 './/a[contains(@class,"link-title")]/@href'
    * css取文本
    	'a.link-title::text'
    * css取属性
    	'img.image-scale::attr(src)'
    	
    
  • 重点2

    .extract_first()	取一个
    .extract()			取所有
    
import scrapy
from bs4 import BeautifulSoup


class CnblogsSpider(scrapy.Spider):
    name = 'cnblogs'
    allowed_domains = ['www.cnblogs.com']
    start_urls = ['http://www.cnblogs.com/']

    def parse(self, response):
        # response类似于requests模块的response对象
        # print(response.text)
        # 返回的数据,解析数据

方式1:使用bs4(不用了)

# 方式一:使用bs4
        soup = BeautifulSoup(response.text, 'lxml')
        article_list = soup.find_all(class_='post-item')
        for article in article_list:
            title_name = article.find(name='a', class_='post-item-title').text
            print(title_name)

方式2:scrapy自带的解析> css解析

 article_list = response.css('article.post-item')
        for article in article_list:
            title_name = article.css('section>div>a::text').extract_first()
            author_img = article.css('p.post-item-summary>a>img::attr(src)').extract_first()
            desc_list = article.css('p.post-item-summary::text').extract()
            desc = desc_list[0].replace('\n', '').replace(' ', '')
            if not desc:
                desc = desc_list[1].replace('\n', '').replace(' ', '')

            author_name = article.css('section>footer>a>span::text').extract_first()
            article_date = article.css('section>footer>span>span::text').extract_first()
            # 文章详情内容,因为在下一页,先不考虑
            print('''
            文章标题:%s
            作者标题:%s
            摘要:%s
            作者名字:%s
            发布日期:%s
            ''' % (title_name, author_img, desc, author_name, article_date))

方式3:scrapy自带的解析> xpath解析

article_list = response.xpath('//article[contains(@class,"post-item")]')
        for article in article_list:
            title_name = article.xpath('./section/div/a/text()').extract_first()
            author_img = article.xpath('./section/div/p//img/@src').extract_first()
            desc_list = article.xpath('./section/div/p/text()').extract()
            desc = desc_list[0].replace('\n', '').replace(' ', '')
            if not desc:
                desc = desc_list[1].replace('\n', '').replace(' ', '')
            author_name = article.xpath('./section/footer/a/span/text()').extract_first()
            article_date = article.xpath('./section/footer/span/span/text()').extract_first()
            print('''
                文章标题:%s
                作者标题:%s
                摘要:%s
                作者名字:%s
                发布日期:%s
            ''' % (title_name, author_img, desc, author_name, article_date))

九、settings相关配置,提高爬取效率

基础配置

# 爬虫项目名
BOT_NAME = 'myfirstscrapy'

# 指定爬虫类的py文件的位置
SPIDER_MODULES = ['myfirstscrapy.spiders']
NEWSPIDER_MODULE = 'myfirstscrapy.spiders'

# 用户类型(携带在请求头里)
USER_AGENT = 'myfirstscrapy (+http://www.yourdomain.com)'

# Obey robots.txt rules==>是否遵循爬虫协议
ROBOTSTXT_OBEY = True

# LOG_LEVEL 日志级别
LOG_LEVEL = 'ERROR'  # 报错如果不打印日志,在控制台看不到错误

# 启动线程数(多少个爬虫同时工作)
CONCURRENT_REQUESTS = 32

# Override the default request headers:==>默认请求头
 DEFAULT_REQUEST_HEADERS = {
   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
   'Accept-Language': 'en',
 }
    
# 爬虫中间件
 SPIDER_MIDDLEWARES = {
    'myfirstscrapy.middlewares.MyfirstscrapySpiderMiddleware': 543,
}    

# 下载中间件
 DOWNLOADER_MIDDLEWARES = {
    'myfirstscrapy.middlewares.MyfirstscrapyDownloaderMiddleware': 543,
}
    
# 持久化配置
 ITEM_PIPELINES = {
    'myfirstscrapy.pipelines.MyfirstscrapyPipeline': 300,
 }

增加爬虫的爬取效率

1.增加并发 默认开启线程数为16
	默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改
	CONCURRENT_REQUESTS = 100
值为100相当于并发设置成了100.
2.降低日志级别
	在运行scrapy时会有大量日志信息的输出。为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在settings配置文件写:
	LOG_LEVEL = 'INFO'
3.禁止cookie
	如果不是真的需要cookie,则在scrapy爬取数据时候禁止cookie从而减少CPU的使用率,提高爬取效率。在配置文件中编写:
    	COOKIES_ENABLED = False
4.禁止重试
	对失败的HTTP进行重新请求(重试)会减少爬取速度,因此可以禁止重试。在配置文件中编写:
    RETRY_ENABLED = False
5.减少下载超时
	如果对用一个非常慢的链接进行爬取,减少下载超时可以让卡住的链接快速被放弃,从而提高效率。在配置文件中降序编写:
    DOWNLOAD_TIMEOUT = 10s

十、 持久化方案

  • 保存到硬盘上

  • 两种方案:第二种常用

    • 第一种:了解

      * 解析函数中parse,需要return [{}, {}, {}] # 列表套字典
      * scrapy crawl cnblogs -o 文件名(json, pickle, csv结尾的文件)
      
    • 第二种:使用pipeline 常用的管道形式,可以同时存多个位置的

      1. 在items.py 中写一个类[相当于django的表模型],继承scrapy.Item
      2. 在类中写属性,写字段,所有字段都是scrapy.Field类型
      	eg:	title = scrapy.Field()
      3. 在爬虫中导入类,实例化得到对象,把要保存的数据放到对象中
      	item['title'] = title  【注意:不能用 . 的形式去获取】
          解析类中 yield item
      4. 修改配置文件,指定pipline,数字表示优先级,越小则优先级越大
      	ITEM_PIPELINES = {
              'crawl_cnblogs.pipelines.CrawlCnblogsPipeline': 300,        
          }
      5. 写一个pipline:CrawlCnblogsPipeline
      	* open_spider:数据初始化,打开文件,打开数据库链接
          * process_item:真正存储的地方
          注意: 最后需要return item,交给后续pipeline继续使用
          * close——spider:销毁资源,关闭文件,关闭数据库链接
      

十一、全站爬取cnblogs文章

  • 第一页爬完后,要保存的数据已经保存
  • 之后需要欧两件事情:
    1. 继续爬取下一页数据===>解析洗衣液的地址,包装成request对象
    2. 继续爬取详情页===>解析出详情页的地址,包装成request对象
  • 现在在这里不能保存,因为数据不全,缺少文章详情,我们需要加上文章详情后再一次性保存。

request和response对象传递参数

  • Request创建

    • 在parse中,for循环中,创建Request对象时,传入meta

      yield Request(url=url, callback=self.detail_parse,meta={'item':item})

  • Response对象

    • detail_parse中,通过response取出meta再取出meta里面的item,把文章详情写入。

      yield item

解析下一页并继续爬取

spiders/cnblogs.py
from scrapy import Request
from myfirstscrapy.items import CnblogsItem
import scrapy
from bs4 import BeautifulSoup


class CnblogsSpider(scrapy.Spider):
    name = 'cnblogs'
    allowed_domains = ['www.cnblogs.com']
    start_urls = ['http://www.cnblogs.com/']

    def parse(self, response):
        # item = CnblogsItem()  # 外面定义,会有问题
        article_list = response.xpath('//article[contains(@class,"post-item")]')
        for article in article_list:
            item = CnblogsItem()  # 定义在for内部,每次都是一个新对象
            title_name = article.xpath('./section/div/a/text()').extract_first()
            author_img = article.xpath('./section/div/p//img/@src').extract_first()
            desc_list = article.xpath('./section/div/p/text()').extract()
            desc = desc_list[0].replace('\n', '').replace(' ', '')
            if not desc:
                desc = desc_list[1].replace('\n', '').replace(' ', '')
            author_name = article.xpath('./section/footer/a/span/text()').extract_first()
            article_date = article.xpath('./section/footer/span/span/text()').extract_first()
            url = article.xpath('./section/div/a/@href').extract_first()

            item['title_name'] = title_name
            item['author_img'] = author_img
            item['desc'] = desc
            item['author_name'] = author_name
            item['article_date'] = article_date
            item['url'] = url
            # print(url)
            # 现在不存了,因为数据不全,等全了以后再存,继续爬取,就要创建Request对象
            # 详情页面,使用self.detail_parse解析
            yield Request(url=url, callback=self.detail_parse, meta={'item': item})

        # 解析出下一页地址
        # css
        next_url = 'https://www.cnblogs.com' + response.css('div.pager>a:last-child::attr(href)').extract_first()
        print(next_url)
        yield Request(url=next_url, callback=self.parse)

    def detail_parse(self, response):
        # print(len(response.text))
        item = response.meta.get('item')
        # 解析详情
        article_content = response.css('div.post').extract_first()
        # print(article_content)
        # print('===================')
        # 把详情,写入当前meta中得item中
        item['article_content'] = str(article_content)
        yield item

items.py
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class CnblogsItem(scrapy.Item):
    # # define the fields for your item here like:
    # # name = scrapy.Field()
    # pass
    title_name = scrapy.Field()
    author_img = scrapy.Field()
    desc = scrapy.Field()
    author_name = scrapy.Field()
    article_date = scrapy.Field()
    url = scrapy.Field()
    article_content = scrapy.Field() # 文章详情
pipelines.py
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html


# useful for handling different item types with a single interface
import pymysql
from itemadapter import ItemAdapter


class CnblogsMysqlPipeline:
    def open_spider(self, spider):
        # 打开数据库链接
        self.conn = pymysql.connect(
            user='root',
            password='123',
            host='127.0.0.1',
            database='cnblogs',
            port=3306,
            autocommit=True  # 自动提交,配置后就不用在下面添加 self.conn.commit()
        )
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
        self.cursor.execute(
              'insert into artice (title_name,author_img,`desc`,author_name,article_date,url,article_content) values (%s,%s,%s,%s,%s,%s,%s)',
            args=[item['title_name'], item['author_img'], item['desc'], item['author_name'], item['article_date'],
                  item['url'], item['article_content']])
        # self.conn.commit() # 提交
        return item

    # 关闭数据库
    def close_spider(self, spider):
        self.cursor.close()
        self.conn.close()


class CnblogsFilesPipeline:
    def open_spider(self, spider):
        # cnblogs这个爬虫对象
        self.f = open('cnblogs.txt', 'at', encoding='utf-8')

    def process_item(self, item, spider):
        # 存真正的数据,每次item都会走一次
        print(item)
        # 存文件不用这种方式,最好爬虫启动,把文件打开爬虫结束文件就关闭了
        with open('cnblogs.txt', 'at', encoding='utf-8') as f:
            f.write('文章标题:%s, 文章作者:%s\n' % (item['title_name'], item['author_name']))
            # return item

        self.f.write('文章标题:%s, 文章作者:%s\n' % (item['title_name'], item['author_name']))
        return item

    def close_spider(self, spider):
        print('我关了')
        self.f.close()

十二、爬虫和下载中间件

  • scrapy的所有中间件都写在middlewares.py中,跟django非常像,做一些拦截。

  • 爬虫中间件(用的很少,了解即可)

    	MyfirstscrapySpiderMiddleware
            def process_spider_input(self, response, spider): # 进入爬虫会执行它
            def process_spider_output(self, response, result, spider): #从爬虫出来会执行它
            def process_spider_exception(self, response, exception, spider):#出了异常会执行
            def process_start_requests(self, start_requests, spider):#第一次爬取执行
            def spider_opened(self, spider): #爬虫开启执行
    # 下载中间件
    	MyfirstscrapyDownloaderMiddleware
            def process_request(self, request, spider): # request对象从引擎进入到下载器会执行
        	def process_response(self, request, response, spider):# response对象从下载器进入到引擎会执行
        	def process_exception(self, request, exception, spider):#出异常执行它
        	def spider_opened(self, spider): #爬虫开启执行它
    
    重点:process_request, process_response
    下载中间件的process_request
    * 返回值
    	* return None:继续执行下面的中间件的process_request
    	* return a Response object:不进行下载中间件,直接返回给引擎,引擎把它给爬虫
        * return a Request object:不进入下载中间件,直接返回给引擎,引擎把它放到调度器中。
        * raise IgnoreRequest:process_exception() 抛异常,会执行process_exception
    
    下载中间件的process_response
    * 返回值
    	* return a Response object:正常,会进入到引擎,引擎会把它给爬虫
        * return a Request object:会进入到引擎,引擎会把它放进调度器中, 等待下次被爬
        * raise IgnoreRequest     会执行process_exception
    

标签:xpath,name,python,爬虫,学习,item,scrapy,html,article
From: https://www.cnblogs.com/bjyxxc/p/16964481.html

相关文章

  • 5.python-列表字典混合练习
    疫情管理"""疫情信息管理系统显示菜单选择菜单1键录入疫情信息(地区、新增、现有)2键显示疫情信息3键删除疫情信息......
  • 从稍微懂一点开始的C++学习之路1: 智能指针
    从稍微懂一点开始的C++学习之路1智能指针因为之前一直是搞qt的,没有搞过纯c++,所以现在算得上是刚开始学纯C++。C++的大部分语法其实我都懂,主要的是一些规范,还有内存回收等......
  • 学习微服务你必须了解的设计模式
    前言这里的设计模式不同于我们熟悉的java程序面向对象的23种设计模式,解决方案的元素是类。而是一种更高层的设计模式,他们的解决方案由相互协作的服务构成。一、什么是模式语......
  • python中利用Flask框架实现点赞系统
    前言:Flask框架中建立两上路由(.route('/index'))和(.route('/dianzan')),分别用于首页显示和数据接收显示。完整实例:fromflaskimportFlask,render_templatefromflaskimport......
  • python-requests接入API
    API接入1APIApplicationProgrammingInterface,应用程序编程接口,是软件之间信息交互的桥梁。  2聚合数据(数据获取网站)网址:https://www.juhe.cn/docs/index/o......
  • python_接入API获取疫情风险区域
    importrequestsfrompandasimportDataFrameurl="http://apis.juhe.cn/springTravel/risk?key=d35f34536565d5cfd9289e2c7e7b27db"#接入外部API获取疫情风险区域......
  • 前端学习最后一天
    目录前端学习最后一天一、jQuery查找标签1.基本选择器2.组合选择器3.层级选择器4.属性选择器5.基本筛选器6.表单筛选器7.筛选器方法二、jQuery节点操作1.class操作2.位置操......
  • 今日内容 scrapy的使用 提高爬虫效率
    scrapy架构介绍引擎(ENGINE)   引擎负责控制系统所有组件之间的数据流,并在某些动作发生时触发事件。有关详细信息,请参见上面的数据流部分调度器(SCHEDULER) ......
  • Java学习十三
    1.异常处理能够使一个方法给它的调用者抛出一个异常。2.Java异常是派生自java.lang.Throwable的类的实例。Java提供大量预定义的异常类,例如,Error、Exception、RuntimeExc......
  • abby:python 阿里口碑商家流量分析
    In[1]:importwarningswarnings.filterwarnings('ignore')importpandasaspdimportnumpyasnpimportmatplotlib.pyplotaspltplt.rcParams['font.......