I have a horrid html page that I need to parse.
I'm looking to capture the H2 title - I've managed this. I also need to search for Stock and Stock On Order. These last two fields are held in SPANS. I can't use class : info alone as there many other fields with this class that I need to disregard. I think the only way to do this is by searching the spans with regex.
Here's some sample HTML - note I've removed lots of HTML that I'm not interested in indicated by ...
..
..
<div class="innerListing">
..
..
<div class="title">
<a id="btl00_ContentPlaceHolder105" href="http://****"><h2 id="btl00_ContentPlaceHolder1_Ctrl_SearchResultsWrapper_ctl05_advertTitleWrapper" title="TitleText">
TitleText</h2></a>
<p class="sku">
</p>
</div>
...
<div class="layout">
<span id="btl00_ContentPlaceHolder1_Ctrl_SearchResultsWrapper_ctl05_ProductTypeLabel" class="label">Product Type:</span><span id="ctl00_ContentPlaceHolder1_Ctrl_SearchResultsWrapper_ctl05_ProductType" class="info">3 seat sofa</span>
...
<span id="btl00_ContentPlaceHolder1_Ctrl_SearchResultsWrapper_ctl05_StockLabel" class="label">Stock:</span><span id="ctl00_ContentPlaceHolder1_Ctrl_SearchResultsWrapper_ctl05_Stock" class="info">5</span>
...
<span id="btl00_ContentPlaceHolder1_Ctrl_SearchResultsWrapper_ctl05_StockOnOrderLabel" class="label">On Order:</span><span id="ctl00_ContentPlaceHolder1_Ctrl_SearchResultsWrapper_ctl05_Stockonorder" class="info">1</span>
</div>
Here's my code so far. It works but as mentioned above I'm getting too much data i.e. all classes='info'. I only need Stock & SockOnOrder
soup = BeautifulSoup(source_code, "lxml")
#For Title
for header in soup.find_all("div", attrs={'class':'innerListing'}):
title = header.find("h2")
print (title.text.strip())
#For Spans
for layout in soup.find_all("div", attrs={'class':'layout'}):
for info in layout.find_all("span", attrs={'class':'info'}):
print (info.text.strip())
Whats the best way of searching with regex?
If I'm understanding your question correctly, do you only want all the spans that have Stock in the id attribute?
If so, you could change your second for loop and ignore the ones not related to Stock/StockonOrder:
#For Spans
for layout in soup.find_all("div", attrs={'class':'layout'}):
for info in layout.find_all("span", attrs={'class':'info', "id":True}):
if "Stock" in info["id"]:
print (info.text.strip())
Note: You would need to add an extra attribute in your find_all call ("id":True) to avoid any KeyErrors. This is just in case there are some span tags that don't have any IDs - so that we may filter them out.
Related
I am trying to scrape some sports game data and I have ran into some issues with my code. Eventually I will move this data into a dataframe and then eventually a database.
I am trying to scrape some sports data.
In the code, I have found the class element of one of the headers I would like to parse. There are multiple h1's in the HTML I am parsing.
<div class="type-game">
<div class="type">NHL Regular Season</div>
<h1>Blackhawks vs. Ducks</h1>
</div>
With this HTML structure, how can I get the h1 to return to a string I can use to populate a dataframe?
Code I have tried so far is:
req = requests.get(url) # + str(page) + '/')
soup = bs(req.text, 'html.parser')
stype = soup.find('h1', class_ ='type-game')
print(stype)
This code returns "None". I have checked other articles on here and nothing has worked so far.
For the next level of my question, is there a way to create a For loop or similar to go through all of the pages (website is numbered sequentially for events) for any games that contain a string?
For example, if I wanted to only save games that have the Chicago Blackhawks in the h1 for the div element that has class= type-game?
Pseudocode would be something like this:
For webpages 1 to 10000:
if class_='type-game' 'h1' contains "Blackhawks"
then proceed with parsing the code
if not, skip the code and go to the next webpage
I know this is a little open ended, but I have a good VBA background and trying to apply those coding ideas to Python has been a challenge.
Select your elements more specific for example with css selectors:
soup.select('h1:-soup-contains("Blackhawks")')
or
soup.select('div.type-game h1:-soup-contains("Blackhawks")')
To get the text from a tag just use .text or get_text()
for e in soup.select('h1:-soup-contains("Blackhawks")'):
print(e.text)
Example
html='''
<div class="type-game">
<div class="type">NHL Regular Season</div>
<h1>Blackhawks vs. Ducks</h1>
</div>
<div class="type-game">
<div class="type">NHL Regular Season</div>
<h1>Hawks vs. Ducks</h1>
</div>
<div class="type-game">
<div class="type">NHL Regular Season</div>
<h1>Ducks vs. Blackhawks</h1>
</div>
'''
soup = BeautifulSoup(html,'lxml')
for e in soup.select('h1:-soup-contains("Blackhawks")'):
print(e.text)
Output
Blackhawks vs. Ducks
Ducks vs. Blackhawks
EDIT
for e in soup.select('div.type-game h1'):
if 'Blackhawks' in e:
pint(e.text)#or do what ever is to do
I was using BeautifulSoup to extract the job title from indeed, there are s span <>tags which one of them contains the title info.
the h2 tagļ¼
<h2 class="jobTitle jobTitle-newJob">
<div class="new topLeft holisticNewBlue desktop">
<span class="label">new</span>
</div>
<span title="Entry Level Software Developer">Entry Level Software Developer</span>
</h2>
Here`s a piece of my code sample:
divs = soup.find_all("div", class_="job_seen_beacon")
for item in divs:
title_span = item.find('h2', class_="jobTitle")
title = title_span.find_all(title=True)
when running it, I can only get the list that contains the title.
[<span title="Entry Level Software Developer">Entry Level Software Developer</span>]
How can extract the title text from it, or is there another way to perform this task?
You need to get It's text property.
title = [span.text for span in title_span.find_all(title=True)]
My guess, there will be only one title, you can use:
title = title_span.find(title=True)
Details: MacOS, Python3, BeautifulSoup4
I am new to Python and even newer to BeautifulSoup so please excuse any beginner mistakes here. I am attempting to scrape html pages which do not heavily differentiate their tags by classes or div ids. In other words, I am trying to scrape the middle section of a list. The list will have an unpredictable amount of tags and elements (sometimes they use an unordered list, other times they are using a description list) so what I am scraping is fairly unpredictable, however, I do have two known variables and those would be the header string text I want to START at and the header string text I want to END at.
I have assembled the following example html to test this on:
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">First Section Title - Known Variable or String</h3>
</div>
</div>
<div>
<ul class="unstyled">
<li>Item1</li>
<li>Item2</li>
<li>Empty LI Tags Also Exist</li>
</ul>
<dl class="dl-horizontal">
<dt>Title of some description list</dt>
<dd>Another item may exist here</dd>
</dl>
</div>
<div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Another Section Title</h3>
</div>
</div>
<ul class="unstyled">
<li>Item1</li>
<li></li>
</ul>
<dl class="dl-horizontal">
<dt>Another Description List Title</dt>
<dd>Another item may exist here</dd>
<dt>And here</dt>
<dd>And Here</dd>
</dl>
</div>
<div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Section Title (String) I Wish To Stop At - Known Variable or String</h3>
</div>
</div>
</div>
Again, using the above model, I want to start at the first section I listed and end at the known text string of a particular section towards the bottom.
I have listed my Python script below. So far, the following Python is grabbing the correct information, however, I do not believe it will work under all circumstances, and there is probably a more efficient way to go about this. Here are some of the issues I believe are in my script:
My script is rather static - while it appears to start at the correct header, I have pieced out two sections separately as I do not believe my For loop is working the way it should be (I do not think ##Section 2 should be needed if written correctly).
Because my For loop is likely not doing what I probably think it is (I'd like it to iterate through the sections) I never had to define the stopping point (the string of text at the section I wish to stop at).
Since I am not convinced the loop is working correctly, I do not believe this will handle any curveballs I am thrown by the site - for example variable numbers of items on the list and if they add an additional section I would want between the "Beginning section" and "Ending section" defined.
I believe what needs to happen is:
Librarys need to be imported
Locate first section
Find next sibling
Keep finding siblings and returning text until the stop string matches
Python:
##Scrape
#import beautifulsoup and requests library
from bs4 import BeautifulSoup
import requests
soup = BeautifulSoup(open("mock.html"), "html.parser")#BeautifulSoup(page.read())
#Begin by grabbing the section
stuff = soup.find_all(class_="panel-heading")
#Search for the first section title text string
next_elem = soup.find(text="First Section Title - Known Variable or String").findNext('li').contents[0]
#Attempt to scan the remainder of the section, starting with the next line item
next_next = next_elem.parent.find_next_sibling()
for item in next_next.findAll('li','dt','dd'):
if isinstance(item, Tag):
print(item.text)
print(next_elem)
print(next_next.text)
##Section 2 - I'd like to cut this out
s2_elem = soup.find(text="Another Section Title").findNext('li').contents[0]
s2_nxnx = s2_elem.parent.find_next_sibling()
s2_nxnxnx = s2_nxnx.parent.find_next_sibling()
print(s2_elem)
print(s2_nxnx.text)
print(s2_nxnxnx.text)
You could use a variable to spot when you are between search_start and search_end:
from bs4 import BeautifulSoup, Tag
import requests
search_start = "First Section Title - Known Variable or String"
search_end = "Section Title (String) I Wish To Stop At - Known Variable or String"
soup = BeautifulSoup(open("mock.html"), "html.parser")
start = False
for el in soup.find_all(['li', 'dt', 'dd', 'h3']):
if el.name == 'h3':
if el.text == search_start:
start = True
elif el.text == search_end:
break
elif start and isinstance(el, Tag):
print(el.text)
This would give you the following output:
Item1
Item2
Empty LI Tags Also Exist
Title of some description list
Another item may exist here
Item1
Another Description List Title
Another item may exist here
And here
And Here
I've written some script in python using regex to fetch text from certain p tags but he script is giving me empty list.
This is the magnetic portion of html elements:
<div class="result__links">
<p class="result__outcome u-hide-phablet">Kolkata Knight Riders won by 7 wickets</p>
<p class="result__info u-hide-phablet">
Match 15, 20:00 IST (14:30 GMT), Sawai Mansingh Stadium, Jaipur
</p>
<a class="result__button result__button--mc btn" href="/match/2018/15?tab=scorecard">Match Centre</a>
</div>
How do I fetch the text of p tag wrapped within the below class?
classs='result__info u-hide-phablet'
The purpose is to fetch the text of above mentioned tag using regex.
This is what I've tried so far:
winner = soup.find_all('p',class_="result__outcome u-hide-phablet")
win_list = re.findall(r'>(.*?)</p>', str(winner))
The above portion produces empty list. Any help on this will be highly appreciated.
Post script: I'm looking for any solution related to regex.
For accessing the tags you are interested in you can do:
for p in soup.findAll("p", {"class" : "result__outcome u-hide-phablet"}):
tags_text = p.text
In the same way for span you need to do:
for span in soup.findAll("span", {"class" : "result__score result__score--winner"}):
tags_text = span.text
That is to get the text in each tag, as you have asked in your question.
for link in data_links:
driver.get(link)
review_dict = {}
# get the size of company
size = driver.find_element_by_xpath('//[#id="EmpBasicInfo"]//span')
#location = ??? need to get this part as well.
my concern:
I am trying to scrape a website. I am using selenium/python to scrape the "501 to 1000 employees" and "Biotech & Pharmaceuticals" from the span, but I am not able to extract the text element from the website using xpath.I have tried getText, get attribute everything. Please, help!
This is the output for each iteration:I am not getting the text value.
Thank you in advance!
It seems you want only the text, instead of interacting with some element, one solution is to use BeautifulSoup to parse the html for you, with selenium getting the code built by JavaScript, you should first get the html content with html = driver.page_source, and then you can do something like:
html ='''
<div id="CompanyContainer">
<div id="EmpBasicInfo">
<div class="">
<div class="infoEntity"></div>
<div class="infoEntity">
<label>Industry</label>
<span class="value">Woodcliff</span>
</div>
<div class="infoEntity">
<label>Size</label>
<span class="value">501 to 1000 employees</span>
</div>
</div>
</div>
</div>
''' # Just a sample, since I don't have the actual page to interact with.
soup = BeautifulSoup(html, 'html.parser')
>>> soup.find("div", {"id":"EmpBasicInfo"}).findAll("div", {"class":"infoEntity"})[2].find("span").text
'501 to 1000 employees'
Or, of course, avoiding specific indexing and looking for the <label>Size</label>, it should be more readable:
>>> [a.span.text for a in soup.findAll("div", {"class":"infoEntity"}) if (a.label and a.label.text == 'Size')]
['501 to 1000 employees']
Using selenium you can do:
>>> driver.find_element_by_xpath("//*[#id='EmpBasicInfo']/div[1]/div/div[3]/span").text
'501 to 1000 employees'