I'm using GeckoFX and a regex in C# to make a YouTube video channel scraper. I want to get the URL of all videos from a selected channel.
I want to use GeckoFX (the Firefox rendering engine) to go to the videos section and click the Load more button until every video shows.
I am using this code to click Load more over and over:
javascript:(function() {
var LoadButton, IntervalCLB;
IntervalCLB = setInterval(_clickLoadButton, 100);
function _clickLoadButton() {
LoadButton = document.getElementsByClassName('load-more-button');
if (LoadButton.length > 0) {
LoadButton[0].click();
}
else {
clearInterval(IntervalCLB);
alert('Finished - Clicked all "Load More" Buttons.');
}
}
})();
I want to write something like that in C#.
My code looks like:
System.Threading.Thread.Sleep(1000);
GeckoDocument document = geckoWebBrowser1.Document;
GeckoHtmlElement Male = (GeckoHtmlElement)document.GetElementsByClassName("load-more-button")[0];
if ( Male != null ) {
Male.Click();
}
But that just clicks Load more once after one second.
How can I make it loop until the Load more button disappears?
Timer timer = new Timer(1000);
timer.Elapsed += ( sender, e ) => {
GeckoDocument document = geckoWebBrowser1.Document;
GeckoHtmlElement Male = (GeckoHtmlElement)document.GetElementsByClassName("load-more-button")[0];
if ( Male != null ) {
Male.Click();
}
};
timer.Start();
But from practical side I recommend you to look into YouTube API: https://developers.google.com/youtube/v3/code_samples/dotnet
Related
What should the program do? Click on every Button on the site.
By bybut = By.XPath("//span[#class='Button']");
var element = driver.FindElement(bybut);
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
for (int i = 0; i < 99; i++)
{
// Scroll element into view (orange rectangle on my picture)
js.ExecuteScript("arguments[0].scrollIntoView(true);", element);
// Time for scrolling
System.Threading.Thread.Sleep(2000);
// Click on Button
driver.FindElement(By.XPath("//span[#class='Button']")).Click();
}
On the internet site, if you click on the button, it will be removed.
My Problem:
If the For-Loop repeated, it comes to an error, because the next button is already in my view frame. How can I check, if a button is already into view?
Do you have any other solutions? Thanks in advance!
YOu can try below code :_
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
List<WebElement> displayedOptions = driver.FindElements(//span[#class='Button']);
for (WebElement option : displayedOptions)
{
try{
js.ExecuteScript("arguments[0].scrollIntoView(true);", option );
System.Threading.Thread.Sleep(2000);
// Click on Button
driver.FindElement(By.XPath("//span[#class='Button']")).Click();
}catch(WebException E){
}
I have an array of button created dynamically, suppose 8 buttons, what I want is that when I click a particular button its background picture is changed and the name of button is stored in a linked list. When I click the same button again the background picture goes back to the original and the button name is deleted from linked list. Now I am able to do the first part, the second click is not working as I want it to.
Basically it's a datastructures project (shopping store) therefore I am using linked list, I have a linked list whose content is displayed through picture boxes[] and labels. Here what i am trying to do is when I click the picture box, the content of that particular node is added to a new linked list (added to the cart) and when I click on the picturebox again that particular item is deleted from the linked list (removed from the cart). Clicking it for the first time it is doing what i want it to do but the second click is not really working.
It's a datastructures project therefore I can't really use any built in classes for linked list, I had to write all methods myself and I did and they work.
cb[i].Click += (sender, e)=>{
if (flag == 0) {
// Console.WriteLine(obj.Retrieve(index).NodeContent);
// Console.WriteLine(obj.Retrieve(index).number);
inv.Add(obj.Retrieve(index).NodeContent, obj.Retrieve(index).number);
bill += Convert.ToInt32(obj.Retrieve(index).number);
cb[index].Image = Image.FromFile(#"F:\uni work\3rd semester\project images\rcart.jpg");
flag++;
}
else if (flag == 1)
{
// Console.WriteLine(bill);
bill -= Convert.ToInt32(obj.Retrieve(index).number);
// Console.WriteLine(bill);
inv.Delete(index);
cb[index].Image = Image.FromFile(#"F:\uni work\3rd semester\project images\cart.png");
flag--;
}
Since you are using a LinkedList it does have a Contains Method and a Remove Method that take a string. You haven't specified exactly what your problem is this should work. When you assign images to a control you loose the information that tells you what Image it is.
public partial class Form1 : Form
{
LinkedList<String> myList = new LinkedList<String>();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 8; i++)
{
Button b = new Button() { Height = 30, Width = 70, Location = new Point(i, 50 * i),Name = "NewButton" + (i + 1).ToString() , Tag=i};
b.Click += b_Click;
this.Controls.Add(b);
}
}
void b_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
if(myList.Contains(b.Name)) //Check if button is in the List then Change Picture and remove
{
b.BackgroundImage = Properties.Resources.Peg_Blue;
myList.Remove(b.Name);
}
else
{
b.BackgroundImage = Properties.Resources.Peg_Red;
myList.AddLast(b.Name);
}
}
}
Why not create a class for each button, containing the two images and switch between them on each click?
So I'm working on Windows Phone Project based on music shuffling. I have one xaml page that display Songs in Queue, code file contain List<> that add all song in list but this task take more time.
When i Click a Button to navigate(or show queue)to page my app still remain same page for 4-5 second.
I want that how can I make some code in xaml.cs file that run after page is loaded.
After page loaded I show Progress Indicator and when all data completely in List<> elements, I show a Songs.
My code:
private void Event()
{
currentQueueData = MediaPlayer.Queue;
List<QueueData> boundedQueueData = new List<QueueData>();
SetProIndicator(true);
SystemTray.ProgressIndicator.Text = "Loading...";
if (currentQueueData.Count != 0)
{
for (int i = currentQueueData.ActiveSongIndex, k = 0; i < totalqueueCount; i++)
{
loadedqueueSongs[k] = currentQueueData[i];
boundedQueueData.Add(new QueueData()
{
queueSongIndex = k++,
queueSongName = currentQueueData[i].Name,
queueSongAlbum = currentQueueData[i].Album.Name + ",",
queueSongArtist = " " + currentQueueData[i].Artist.Name,
});
}
queueList.ItemsSource = boundedQueueData;
SetProIndicator(false);
//queueList.Foreground = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));
}
else
{
boundedQueueData.Add(new QueueData()
{
queueSongIndex = 0,
queueSongName = "Currently Queue Is Empty",
queueSongAlbum = "",
queueSongArtist = "",
});
queueList.ItemsSource = boundedQueueData;
}
}
If it is Possible that Event() function load after MyPage.xaml page is loaded?
Following the comments on the question, one possible answer would be to suscribe to the Loaded event of your page and call the Event method from there.
Really simple example:
public MyPage()
{
this.Loaded += PageLoaded;
}
void PageLoaded(object sender, RoutedEventArgs e)
{
this.Event();
}
So what we did is to suscribe to the loaded event on the constructor of the page. By the time the page is loaded, you will be able to call your Event method from the callback.
I have a WebView on my app and I can't change the html file("target=_blank" link types). But some links on the page makes my app open them on the system browser. How can I disallow this action?
Thanks.
In the NavigationCompleted event handler run this script:
webView.InvokeScriptAsync("eval", new[]
{
#"(function()
{
var hyperlinks = document.getElementsByTagName('a');
for(var i = 0; i < hyperlinks.length; i++)
{
if(hyperlinks[i].getAttribute('target') != null)
{
hyperlinks[i].setAttribute('target', '_self');
}
}
})()"
});
On Windows 10, you can use WebView.NewWindowRequested:
private void WebView1_NewWindowRequested(
WebView sender,
WebViewNewWindowRequestedEventArgs args)
{
Debug.WriteLine(args.Uri);
args.Handled = true; // Prevent the browser from being launched.
}
There is a navigation starting event. It have a cancel property that can be used to cancel the navigation. Maybe this will work for you?
http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.webview.navigationstarting
Stumbled on this myself recently, and I want to add that even though user2269867's answer is a viable solution, it might not work in certain situations.
For example, system browser will not only open if user click a link with target="_blank" attribute, but also if window.open() function called in javascript. Moreover, even removing all 'target' attributes won't work if a page loading some content dynamically and changing DOM after your script is already finished executing.
To solve all problems above, you need to override window.open function and also check for 'target' attribute not once, but every time user click something. Here is script that covers those cases:
function selfOrParentHasAttribute(e, attributeName) {
var el = e.srcElement || e.target;
if (el.hasAttribute(attributeName)) {
return el;
}
else {
while (el = el.parentNode) {
if (el.hasAttribute(attributeName)) {
return el;
}
}
}
return false;
}
var targetAttributeName = "target";
document.addEventListener("click", function (e) {
var el = selfOrParentHasAttribute(e, targetAttributeName);
if (el) {
if ((el.getAttribute(targetAttributeName) == "_blank") ||
(el.getAttribute(targetAttributeName) == "_new"))
{
el.removeAttribute(targetAttributeName);
}
}
});
window.open = function () {
return function (url) {
window.location.href = url;
};
}(window.open);
My js skills aren't ideal, so feel free to modify.
Also don't forget that, as kiewic mentioned, for Windows 10 there is WebView.NewWindowRequested event which solves this issue more natural.
If you just want to show the page and not allow any action to be done on that page I would look into WebViewBrush. The WebViewBrush will basically screenshot the website and the users will not be able to use any links or anything else on that page, it will turn into a read-only page. I believe this is what you are asking for.
More info on WebViewBrush can be found here: http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.webviewbrush
If you can edit HTML of the page and NavigateToString(), then add <base target='_blank'/> in the <head>
I need to be able to place the captcha image into a picturebox on my form, the reason being that I need to zoom the captcha image for the visualy impaired users.
It appears to be such a simple task, just take the image from the web page and put it into a picturebox but it is turning out to be not so simple.
i have WebBrowser control in form and for registration in one of site, i need captcha image in picture box. problem is that captcha image is generated by JavaScript, when java script runs then it gives url of captcha image. but every time when java script runs, captcha image goes change. i just want that captcha image which is on WebBrowser control current page.
Any help would be greatly appreciated.
here is my code.
public void FacebookRegistration()
{
HTMLDoc = (mshtml.HTMLDocument)WBrowser.Document.DomDocument;
iHTMLCol = HTMLDoc.getElementsByTagName("input");
foreach (IHTMLElement iHTMLEle in iHTMLCol)
{
if (iHTMLEle.getAttribute("name", 0) != null)
{
strAttriName = iHTMLEle.getAttribute("name", 0).ToString();
if (strAttriName == "firstname")
{
iHTMLEle.setAttribute("value", FirstName, 0);
continue;
}
if (strAttriName == "lastname")
{
iHTMLEle.setAttribute("value", LastName, 0);
continue;
}
if (strAttriName == "reg_email__")
{
iHTMLEle.setAttribute("value", EmailID, 0);
continue;
}
if (strAttriName == "reg_passwd__")
{
string s = GetRandomString();
Random ran = new Random();
iHTMLEle.setAttribute("value", s+ran.Next(1111,9999), 0);
break;
}
}
}
iHTMLCol = HTMLDoc.getElementsByTagName("option");
foreach (IHTMLElement iHTMLEle in iHTMLCol)
{
try
{
if (iHTMLEle.innerText.Contains("Male"))
{
iHTMLEle.setAttribute("selected", "selected",0);
}
if (iHTMLEle.innerText.Contains("Jun"))
{
iHTMLEle.setAttribute("selected", "selected", 0);
}
Random ran = new Random();
if (iHTMLEle.innerText.Contains("4"))
{
iHTMLEle.setAttribute("selected", "selected", 0);
}
Random ran1 = new Random();
if (iHTMLEle.innerText.Contains(ran1.Next(1920,1985).ToString()))
{
iHTMLEle.setAttribute("selected", "selected", 0);
}
}
catch { }
}
iHTMLCol = HTMLDoc.getElementsByTagName("input");
int i = 0;
foreach (IHTMLElement iHTMLEle in iHTMLCol)
{
string s = iHTMLEle.className;
if (iHTMLEle.className == "UIButton_Text" && iHTMLEle.getAttribute("value", 0).ToString() == "Sign Up")
{
if (i != 0)
{
iHTMLEle.click();
break;
}
i++;
}
}
private void WBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (CurrentSocial == "facebook")
{
FacebookRegistration();
}
}
}
in the registration page of facebook.com, there is captcha and if you go to page source then you will see only this:
<input type="hidden" id="captcha_persist_data" name="captcha_persist_data" value="AAAAAQAQiCw5zhFGOsVF6TbDBX8d_wAAAGvqENqFy5KkvMip5AIv3QSF7BS7goiHfAC7fTkzr8hW61cq3s1d23Tw7m-WAi-21Uzt1l3frkLf4obBEuZZMwga_hbcUhnWXu4P382QsJ7J0WtAbo5USXWuVjzv_KD1SMyTWhf34AGorQd27dFqZc0a" /?;
and in this input tag, i found url of that javascript which gives captcha url
javascript url: http://api.recaptcha.net/challenge?k=6LezHAAAAAAAADqVjseQ3ctG3ocfQs2Elo1FTa_a&ajax=1&xcachestop=0.31520985781374&authp=nonce.tt.time.new_audio_default&psig=H48rD9d3_QogBfxxKAmzFZ7CG10&nonce=hl77BQn58EsYsPpPwQ2TIA&tt=r3zaWETv27-0igoIw5ndwnHt_W4&time=1256413208&new_audio_default=1
if you browse this url you will get captcha url like this:
var RecaptchaState = {
challenge : '02UflxsCli4nYg-oG48n5bNDm6ywMlvE62UwXQssF__eJAfSiv2TXuac-1tbu2FThwakgH65IdExWDy9qyr1sYbRuwyQFZD7Dk1eE_fXuoSn9tliqnYeMq__LEF6-GTEm0H6TChOtvpwL2G3C1BsBriw8FFaKqkaTwbNoJeAfzI_j9qYnPaqtHJYillevhRsxyaQVYfLvqai7p0Sfu3849BFpamlbfE3to3KTXi5cZ0xlmuGkMkuZhvq_GyK_z-ZXq9z_Ls8xZlywN0jlIOsSEvI9QJq_69X-X3Moq9lFBcmqWYaKbf7faRQt19aJGB4DdBC1PqQIC',
timeout : 25000,
server : 'http://api.recaptcha.net/',
site : '6LezHAAAAAAAADqVjseQ3ctG3ocfQs2Elo1FTa_a',
error_message : '',
programming_error : '',
is_incorrect : false
};
Recaptcha.challenge_callback();
and original captcha url look like this:
http://api.recaptcha.net/image?c=027CxC4LbBbzVJKy-1xX_wRBf7Gmi4AvgikDVaKeYjBCmiX4XBzGymWC7XRfWx4LLQgfscKnfeB7U305MhlVN0X4vAkrK84ac3jybRJ3UJPUQ8rnlJOS7lqNqpRpolYSd6WBxMShhrzqbx-5ScL0JAsN7cJRMLMqeQsPHg1QB7g4kp4KxKO1aEONsUibahnCC8baLHGSIYJ5Q1Gcr1MPvJ9i_a5qQCilT1tWXwAKE_fkVGi31_un3OxHbNm9UmMemRp7IZ9C9ZLU4IjMApxVJOWXMYqjt588z_ZVcYG2dtY6Dh0b4R1aAQcp0UXFTggdWtsjPw7wIC
then you will get captcha, but is is not what i want , because javascript everytime changes the capthca image. so i dont get captcha which is currently being shown in webbrowser
You can copy the image to the clipboard and read from there. Alternatively you can parse the page to get the image's URL and see if you can dig the image file out of the cache
How To Programmatically Copy an IMG Element to the Clipboard
Would it be possible to use reCaptcha.net instead? You register for free, add the script to your page and then they do the rest. They may not have zooming for the visually impaired, but they do have text-to-speech. No sense in reinventing the wheel if you don't have to. Of course you'd need access to the internet on your page so this could be a problem if your site is an intranet or private network of some sort. Hope that helps.