先,介绍一下正则的概念。正则表达式是由一个字符序列形成的搜索模式。当你在文本中搜索数据时,你可以用搜索模式来描述你要查询的内容。正则表达式可用于所有文本搜索和文本替换的操作。其基本语法结构如下:
/正则表达式主体/修饰符(可选)
其中,修饰符部分是可选内容。常见的修饰符有:
修饰符描述i执行对大小写不敏感的匹配。g执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。m执行多行匹配。
另外,JS的正则表达式模式和Python相似,具体可以参考资料2所示。主要包括:方括号、元字符和量词等。
支持正则表达式的String对象的方法如下:
方法描述FFIEsearch检索与正则表达式相匹配的值。14match找到一个或多个正则表达式的匹配。14replace替换与正则表达式匹配的子串。14split把字符串分割为字符串数组。14
其中,match会返回匹配上的内容,比较常用。
以下给出一个利用JavaScript正则获取字符串括号内的内容的小例子:
encode='aa(ddsdd)gh'var re=/\([^\)]+\)/gencode=encode.match(re)[0]encode=encode.substring(1,encode.length-1) //ddsdd
原文链接:https://blog.csdn.net/sinat_23133783/article/details/109082113?utm_medium=distribute.pc_category.none-task-blog-hot-3.nonecase&depth_1-utm_source=distribute.pc_category.none-task-blog-hot-3.nonecase&request_id=
作者:麦片加奶不加糖
extract提取
注:extract 应与request保持同一层级
注:变量名的前面要有 -
# 获取响应数据: 响应行(200,ok)\响应头
- config:
name: 测试百度网站
base_url: https://www.baidu.com
- test:
name: 接口名称 百度接口
request:
url: /
method: GET
extract: # 提取值存储到变量中
- code: status_code # 响应码
- info: reason # ok
- header_Content: headers.Content-Type # 响应头部
validate:
- eq: [$code,200] # 引用变量 $变量名
- eq: [$info,"OK"]
- eq: [$header_Content,'text/html']
extract 解析响应正文(支持正则)
通过 extract 提取响应正文的数据并存储到变量中(可使用正则提取),如下:
注:如果断言为中文,加上headers头部的Accept-Language即可,后面有专门写的中文乱码解码的问题解决
# 获取响应数据 响应正文(支持正则)
- config:
name: 百度
base_url: https://www.baidu.com
- test:
name: 百度主页
request:
url: /
method: GET
headers: # 如果断言为中文的话,加上headers的Accept-Language即可
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36
extract:
- title: <title>(.+?)</title> # 可以使用正则表达式提取
validate:
- eq: [$title,"百度一下,你就知道"]
extract 解析响应正文(支持json)
通过 extract 提取响应正文的数据并存储到变量中(提取json数据),格式以content为根节点:content.key.key.key ;如下:
次爬取用到的知识点有:
正文
1) 找到对应的URL, URL里的参数正是Query String Parameters的参数, 且请求方式是GET
2) 我们请求该URL得到内容就是"Response"里的内容, 那么点击它来确认信息.
3) 下拉看到"男装"字样, 那么再往下找, 并没有发现有关"男装"的商品信息.
4) 任意复制一个商品信息, 空白处右击再点击"查看网页源代码", 在源码查找该商品, 即可看到该商品的信息.
5) 对比网页源代码和"Response"响应内容, 发现源代码<script>..........</script>中的商品信息被替换, 这便是采用了JS加密
6) 如果去请求上面的URL, 得到的则是加密过的信息, 这时就可以利用Selenium库来模拟浏览器, 进而得到商品信息.
获取单个商品界面
# -*- coding: utf-8 -*- from selenium import webdriver #从selenium导入浏览器驱动 browser=webdriver.Chrome() #声明驱动对象, 即Chrome浏览器 def get_one_page(): '''获取单个页面''' browser.get("https://www.xxxxx.com") #请求网站
# -*- coding: utf-8 -*- from selenium import webdriver from selenium.webdriver.common.by import By #导入元素定位方法模块 from selenium.webdriver.support.ui import WebDriverWait #导入等待判断模块 from selenium.webdriver.support import expected_conditions as EC #导入判断条件模块 browser=webdriver.Chrome() def get_one_page(): '''获取单个页面''' browser.get("https://www.xxxxx.com") input=WebDriverWait(browser,10).until( #等待判断 EC.presence_of_element_located((By.CSS_SELECTOR,"#q"))) #若输入框显示成功,则获取,否则等待 input.send_keys("男装") #输入商品名称
# -*- coding: utf-8 -*- from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC browser=webdriver.Chrome() def get_one_page(): '''获取单个页面''' browser.get("https://www.xxxxx.com") input=WebDriverWait(browser,10).until( EC.presence_of_element_located((By.CSS_SELECTOR,"#q"))) # input.send_keys("男装") button=WebDriverWait(browser,10).until( #等待判断 EC.element_to_be_clickable((By.CSS_SELECTOR,"#J_TSearchForm > div.search-button > button"))) #若按钮可点击, 则获取, 否则等待 button.click()
# -*- coding: utf-8 -*- ? import re from selenium import webdriver from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC browser=webdriver.Chrome() def get_one_page(): '''获取单个页面''' browser.get("https://www.xxxxx.com") input=WebDriverWait(browser, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, "#q"))) input.send_keys("男装") button=WebDriverWait(browser, 10).until( EC.element_to_be_clickable( (By.CSS_SELECTOR, "#J_TSearchForm > div.search-button > button"))) button.click() pages=WebDriverWait(browser, 10).until( # 等待判断 EC.presence_of_element_located( (By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.total"))) # 若总页数加载成功,则获取总页数,否则等待 return pages.text def main(): pages=get_one_page() print(pages) if __name__=='__main__': main()
# -*- coding: utf-8 -*- import re from selenium import webdriver from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC browser=webdriver.Chrome() def get_one_page(): '''获取单个页面''' try: browser.get("https://www.xxxxx.com") input=WebDriverWait(browser,10).until( EC.presence_of_element_located((By.CSS_SELECTOR,"#q"))) input.send_keys("男装") button=WebDriverWait(browser,10).until( EC.element_to_be_clickable((By.CSS_SELECTOR,"#J_TSearchForm > div.search-button > button"))) button.click() pages=WebDriverWait(browser,10).until( EC.presence_of_element_located((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > div.total"))) return pages.text except TimeoutException: return get_one_page() #如果超时,继续获取 def main(): pages=get_one_page() pages=int(re.compile("(\d+)").findall(pages)[0]) #采用正则表达式提取文本中的总页数 print(pages) if __name__=='__main__': main() ?
关于Selenium的更多内容,可参看官方文档https://selenium-python.readthedocs.io/waits.html
获取多个商品界面
采用获取"到第 页"输入框方式, 切换到下一页, 同样是等待判断
需要注意的是, 最后要加入判断: 高亮是否是当前页
def get_next_page(page): try: input=WebDriverWait(browser, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > input"))) # 若输入框加载成功,则获取,否则等待 input.send_keys(page) # 输入页码 button=WebDriverWait(browser, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit"))) # 若按钮可点击,则获取,否则等待 button.click() # 点击按钮 WebDriverWait(browser,10).until( EC.text_to_be_present_in_element((By.CSS_SELECTOR,"#mainsrp-pager > div > div > div > ul > li.item.active > span"),str(page))) # 判断高亮是否是当前页 except TimeoutException: # 超时, 继续请求 return get_next_page(page) def main(): pages=get_one_page() pages=int(re.compile("(\d+)").findall(pages)[0]) for page in range(1,pages+1): get_next_page(page) if __name__=='__main__': main()
获取商品信息
首先, 判断信息是否加载成功, 紧接着获取源码并初始化, 进而解析.
需要注意的是, 在"get_one_page"和"get_next_page"中调用之后, 才可执行
def get_info(): """获取详情""" WebDriverWait(browser,20).until(EC.presence_of_element_located(( By.CSS_SELECTOR,"#mainsrp-itemlist .items .item"))) #判断商品信息是否加载成功 text=browser.page_source #获取网页源码 html=pq(text) #初始化网页源码 items=html('#mainsrp-itemlist .items .item').items() #采用items方法会得到生成器 for item in items: #遍历每个节点对象 data=[] image=item.find(".pic .img").attr("src") #用find方法查找子孙节点,用attr方法获取属性名称 price=item.find(".price").text().strip().replace("\n","") #用text方法获取文本,strip()去掉前后字符串,默认是空格 deal=item.find(".deal-cnt").text()[:-2] title=item.find(".title").text().strip() shop=item.find(".shop").text().strip() location=item.find(".location").text() data.append([shop, location, title, price, deal, image]) print(data)
保存到MySQL数据库
def save_to_mysql(data): """存储到数据库""" # 创建数据库连接对象 db=pymysql.connect(host="localhost",user="root",password="password",port=3306, db="spiders",charset="utf8") # 获取游标 cursor=db.cursor() #创建数据库 cursor.execute("CREATE TABLE IF NOT EXISTS {0}(shop VARCHAR(20),location VARCHAR(10),title VARCHAR(255),price VARCHAR(20),deal VARCHAR(20), image VARCHAR(255))".format("男装")) #SQL语句 sql="INSERT INTO {0} values(%s,%s,%s,%s,%s,%s)".format("男装") try: #传入参数sql,data if cursor.execute(sql,data): #插入数据库 db.commit() print("********已入库**********") except: print("#########入库失败#########") #回滚,相当什么都没做 db.rollback() #关闭数据库 db.close()
完整代码
*请认真填写需求信息,我们会在24小时内与您取得联系。